Skip to content

🪟 🚦 Add base E2E test for new stream table (part 1) #22412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Feb 8, 2023
Merged
2 changes: 2 additions & 0 deletions airbyte-webapp-e2e-tests/cypress/commands/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface ConnectionsList {
}

export interface Destination {
name: string;
destinationDefinitionId: string;
destinationName: string;
destinationId: string;
Expand All @@ -50,6 +51,7 @@ export interface DestinationsList {
}

export interface Source {
name: string;
sourceDefinitionId: string;
sourceName: string;
sourceId: string;
Expand Down
4 changes: 2 additions & 2 deletions airbyte-webapp-e2e-tests/cypress/commands/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const submitButtonClick = () => {
cy.get("button[type=submit]").click();
export const submitButtonClick = (force: boolean = false) => {
cy.get("button[type=submit]").click({ force: force });
};

export const updateField = (field: string, value: string) => {
Expand Down
18 changes: 17 additions & 1 deletion airbyte-webapp-e2e-tests/cypress/commands/interceptors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
export const interceptGetConnectionRequest = () => cy.intercept("/api/v1/web_backend/connections/get").as("getConnection")
export const interceptGetConnectionRequest = () =>
cy.intercept("/api/v1/web_backend/connections/get").as("getConnection");
export const waitForGetConnectionRequest = () => cy.wait("@getConnection");

export const interceptUpdateConnectionRequest = () =>
cy.intercept("/api/v1/web_backend/connections/update").as("updateConnection");
export const waitForUpdateConnectionRequest = () => cy.wait("@updateConnection", { timeout: 10000 });

export const interceptDiscoverSchemaRequest = () =>
cy.intercept("/api/v1/sources/discover_schema").as("discoverSchema");
export const waitForDiscoverSchemaRequest = () => cy.wait("@discoverSchema");

export const interceptCreateConnectionRequest = () =>
cy.intercept("/api/v1/web_backend/connections/create").as("createConnection");
export const waitForCreateConnectionRequest = () => cy.wait("@createConnection");

export const interceptGetSourcesListRequest = () => cy.intercept("/api/v1/sources/list").as("getSourcesList");
export const waitForGetSourcesListRequest = () => cy.wait("@getSourcesList");

export const interceptGetSourceDefinitionsRequest = () =>
cy.intercept("/api/v1/source_definitions/list_for_workspace").as("getSourceDefinitions");
export const waitForGetSourceDefinitionsRequest = () => cy.wait("@getSourceDefinitions");
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { initialSetupCompleted } from "commands/workspaces";
import {
getPostgresCreateDestinationBody,
getPostgresCreateSourceBody,
requestCreateDestination,
requestCreateSource,
requestDeleteConnection,
requestDeleteDestination,
requestDeleteSource,
requestWorkspaceId,
} from "commands/api";
import { appendRandomString, submitButtonClick } from "commands/common";
import { clickNewConnectionButton, visitConnectionsListPage } from "pages/connnectionsListPage";
import {
clickUseExistingConnectorButton,
isAtConnectionOverviewPage,
isAtNewConnectionPage,
isNewConnectionPageHeaderVisible,
selectExistingConnectorFromDropdown,
} from "pages/newConnectionPage";
import {
interceptCreateConnectionRequest,
interceptDiscoverSchemaRequest,
interceptGetSourceDefinitionsRequest,
interceptGetSourcesListRequest,
waitForCreateConnectionRequest,
waitForDiscoverSchemaRequest,
waitForGetSourceDefinitionsRequest,
waitForGetSourcesListRequest,
} from "commands/interceptors";
import { Connection, Destination, Source } from "commands/api/types";
import { selectSchedule } from "pages/replicationPage";
import { runDbQuery } from "commands/db/db";
import { createUsersTableQuery, dropUsersTableQuery } from "commands/db/queries";

// TODO: Disable before merge
describe("New stream table - new connection set up ", () => {
let source: Source;
let destination: Destination;
let connectionId: string;

before(() => {
initialSetupCompleted();
runDbQuery(dropUsersTableQuery);
runDbQuery(createUsersTableQuery);

requestWorkspaceId().then(() => {
const sourceRequestBody = getPostgresCreateSourceBody(appendRandomString("Stream table Source"));
const destinationRequestBody = getPostgresCreateDestinationBody(appendRandomString("Stream table Destination"));

requestCreateSource(sourceRequestBody).then((sourceResponse) => {
source = sourceResponse;
requestCreateDestination(destinationRequestBody).then((destinationResponse) => {
destination = destinationResponse;
});
});
});
});

after(() => {
if (connectionId) {
requestDeleteConnection(connectionId);
}
if (source) {
requestDeleteSource(source.sourceId);
}
if (destination) {
requestDeleteDestination(destination.destinationId);
}
});

it("should open 'New connection' page", () => {
visitConnectionsListPage();
interceptGetSourcesListRequest();
interceptGetSourceDefinitionsRequest();

clickNewConnectionButton();
waitForGetSourcesListRequest();
waitForGetSourceDefinitionsRequest();
});

it("should select existing Source from dropdown and click button", () => {
selectExistingConnectorFromDropdown(source.name);
clickUseExistingConnectorButton("source");
});

it("should select existing Destination from dropdown and click button", () => {
interceptDiscoverSchemaRequest();
selectExistingConnectorFromDropdown(destination.name);
clickUseExistingConnectorButton("destination");
waitForDiscoverSchemaRequest();
});

it("should redirect to 'New connection' settings page with stream table'", () => {
isAtNewConnectionPage();
});

it("should show 'New connection' page header", () => {
isNewConnectionPageHeaderVisible();
});

it("should set 'Replication frequency' to 'Manual'", () => {
selectSchedule("Manual");
});

/*
here will be added more tests to extend the test flow
*/

it("should set up a connection", () => {
interceptCreateConnectionRequest();
submitButtonClick(true);
waitForCreateConnectionRequest().then((interception) => {
assert.isNotNull(interception.response?.statusCode, "200");
expect(interception.request.method).to.eq("POST");

const connection: Partial<Connection> = {
name: `${source.name} <> ${destination.name}`,
scheduleType: "manual",
};
expect(interception.request.body).to.contain(connection);
expect(interception.response?.body).to.contain(connection);

connectionId = interception.response?.body?.connectionId;
});
});

it("should redirect to connection overview page after connection set up", () => {
isAtConnectionOverviewPage(connectionId);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getWorkspaceId } from "commands/api/workspace";
const statusCell = (connectionId: string) => `[data-testId='statusCell-${connectionId}']`;
const changesStatusIcon = (type: string) => `[data-testId='changesStatusIcon-${type}']`;
const manualSyncButton = "button[data-testId='manual-sync-button']";
const newConnectionButton = "button[data-testId='new-connection-button']";

export const visitConnectionsListPage = () => {
cy.intercept("**/web_backend/connections/list").as("listConnections");
Expand All @@ -16,3 +17,7 @@ export const getSchemaChangeIcon = (connection: Connection, type: "breaking" | "

export const getManualSyncButton = (connection: Connection) =>
cy.get(`${statusCell(connection.connectionId)} ${manualSyncButton}`);

export const clickNewConnectionButton = () => {
cy.get(newConnectionButton).click();
};
25 changes: 25 additions & 0 deletions airbyte-webapp-e2e-tests/cypress/pages/newConnectionPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
type ConnectorType = "source" | "destination";
const existingConnectorDropdown = `div[data-testid='entityId']`;
const getExistingConnectorDropdownOption = (connectorName: string) => `div[data-testid='${connectorName}']`;
const useExistingConnectorButton = (connectorType: ConnectorType) =>
`button[data-testid='use-existing-${connectorType}-button']`;

const pageHeaderContainer = `div[data-testid='page-header-container']`;
const newConnectionPageTitle = "New connection";

export const selectExistingConnectorFromDropdown = (connectorName: string) =>
cy
.get(existingConnectorDropdown)
.click()
.within(() => cy.get(getExistingConnectorDropdownOption(connectorName)).click());

export const clickUseExistingConnectorButton = (connectorType: ConnectorType) =>
cy.get(useExistingConnectorButton(connectorType)).click();

export const isNewConnectionPageHeaderVisible = () =>
cy.get(pageHeaderContainer).contains(newConnectionPageTitle).should("be.visible");

// Route checking
export const isAtNewConnectionPage = () => cy.url().should("include", `/connections/new-connection`);
export const isAtConnectionOverviewPage = (connectionId: string) =>
cy.url().should("include", `connections/${connectionId}/status`);
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ export const ConnectionOnboarding: React.FC<ConnectionOnboardingProps> = ({ onCr
</div>
</div>
<div className={styles.footer}>
<Button onClick={() => onCreate()} size="lg" data-id="new-connection">
<Button onClick={() => onCreate()} size="lg" data-testid="new-connection-button">
<FormattedMessage id="connection.onboarding.createFirst" />
</Button>
<FormattedMessage
Expand Down
2 changes: 1 addition & 1 deletion airbyte-webapp/src/components/ui/PageHeader/PageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
middleTitleBlock,
endComponent,
}) => (
<div className={classNames(styles.container)} data-withline={withLine}>
<div className={classNames(styles.container)} data-withline={withLine} data-testid="page-header-container">
<Heading
as="h1"
className={classNames(styles.start, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const AllConnectionsPage: React.FC = () => {
variant="primary"
size="sm"
onClick={() => onCreateClick()}
data-testid="new-connection-button"
>
<FormattedMessage id="connection.newConnection" />
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,12 @@ const ExistingEntityForm: React.FC<IProps> = ({ type, onSubmit }) => {
)}
</Field>
<BottomBlock>
<Button className={styles.submitButton} disabled={isSubmitting} type="submit">
<Button
className={styles.submitButton}
disabled={isSubmitting}
type="submit"
data-testid={`use-existing-${type}-button`}
>
<FormattedMessage id={`connectionForm.${type}Use`} />
</Button>
</BottomBlock>
Expand Down