diff --git a/airbyte-webapp-e2e-tests/cypress/commands/api/types.ts b/airbyte-webapp-e2e-tests/cypress/commands/api/types.ts index ff07d04bf326..f21ebd75b112 100644 --- a/airbyte-webapp-e2e-tests/cypress/commands/api/types.ts +++ b/airbyte-webapp-e2e-tests/cypress/commands/api/types.ts @@ -39,6 +39,7 @@ export interface ConnectionsList { } export interface Destination { + name: string; destinationDefinitionId: string; destinationName: string; destinationId: string; @@ -50,6 +51,7 @@ export interface DestinationsList { } export interface Source { + name: string; sourceDefinitionId: string; sourceName: string; sourceId: string; diff --git a/airbyte-webapp-e2e-tests/cypress/commands/common.ts b/airbyte-webapp-e2e-tests/cypress/commands/common.ts index 80c78caa697b..39ad108232fd 100644 --- a/airbyte-webapp-e2e-tests/cypress/commands/common.ts +++ b/airbyte-webapp-e2e-tests/cypress/commands/common.ts @@ -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) => { diff --git a/airbyte-webapp-e2e-tests/cypress/commands/interceptors.ts b/airbyte-webapp-e2e-tests/cypress/commands/interceptors.ts index 9a35ba0ce386..0cd74091122a 100644 --- a/airbyte-webapp-e2e-tests/cypress/commands/interceptors.ts +++ b/airbyte-webapp-e2e-tests/cypress/commands/interceptors.ts @@ -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"); diff --git a/airbyte-webapp-e2e-tests/cypress/integration/connection/streamTable.spec.ts b/airbyte-webapp-e2e-tests/cypress/integration/connection/streamTable.spec.ts new file mode 100644 index 000000000000..f95a0361ae41 --- /dev/null +++ b/airbyte-webapp-e2e-tests/cypress/integration/connection/streamTable.spec.ts @@ -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 = { + 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); + }); +}); diff --git a/airbyte-webapp-e2e-tests/cypress/pages/connnectionsListPage.ts b/airbyte-webapp-e2e-tests/cypress/pages/connnectionsListPage.ts index e1c7876d252a..bb468f1b2673 100644 --- a/airbyte-webapp-e2e-tests/cypress/pages/connnectionsListPage.ts +++ b/airbyte-webapp-e2e-tests/cypress/pages/connnectionsListPage.ts @@ -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"); @@ -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(); +}; diff --git a/airbyte-webapp-e2e-tests/cypress/pages/newConnectionPage.ts b/airbyte-webapp-e2e-tests/cypress/pages/newConnectionPage.ts new file mode 100644 index 000000000000..d2653cfb96d0 --- /dev/null +++ b/airbyte-webapp-e2e-tests/cypress/pages/newConnectionPage.ts @@ -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`); diff --git a/airbyte-webapp/src/components/connection/ConnectionOnboarding/ConnectionOnboarding.tsx b/airbyte-webapp/src/components/connection/ConnectionOnboarding/ConnectionOnboarding.tsx index 66b77d9f3dd3..035b7de69bf4 100644 --- a/airbyte-webapp/src/components/connection/ConnectionOnboarding/ConnectionOnboarding.tsx +++ b/airbyte-webapp/src/components/connection/ConnectionOnboarding/ConnectionOnboarding.tsx @@ -241,7 +241,7 @@ export const ConnectionOnboarding: React.FC = ({ onCr
- = ({ middleTitleBlock, endComponent, }) => ( -
+
{ variant="primary" size="sm" onClick={() => onCreateClick()} + data-testid="new-connection-button" > diff --git a/airbyte-webapp/src/pages/connections/CreateConnectionPage/ExistingEntityForm.tsx b/airbyte-webapp/src/pages/connections/CreateConnectionPage/ExistingEntityForm.tsx index 4662af50764c..4e235ad3283f 100644 --- a/airbyte-webapp/src/pages/connections/CreateConnectionPage/ExistingEntityForm.tsx +++ b/airbyte-webapp/src/pages/connections/CreateConnectionPage/ExistingEntityForm.tsx @@ -114,7 +114,12 @@ const ExistingEntityForm: React.FC = ({ type, onSubmit }) => { )} -