diff --git a/packages/twenty-e2e-testing/.env.example b/packages/twenty-e2e-testing/.env.example index 9f0b80f99..e64b073c5 100644 --- a/packages/twenty-e2e-testing/.env.example +++ b/packages/twenty-e2e-testing/.env.example @@ -3,18 +3,4 @@ FRONTEND_BASE_URL=http://localhost:3001 BACKEND_BASE_URL=http://localhost:3000 DEFAULT_LOGIN=tim@apple.dev DEFAULT_PASSWORD=Applecar2025 -WEBSITE_URL=https://twenty.com - -# === DO NOT USE, WORK IN PROGRESS === -# This URL must have trailing forward slash as all REST API endpoints have object after it -# Documentation for REST API: https://twenty.com/developers/rest-api/core#/ -# REST_API_BASE_URL=http://localhost:3000/rest/ - -# Documentation for GraphQL API: https://twenty.com/developers/graphql/core -# GRAPHQL_BASE_URL=http://localhost:3000/graphql - -# Without this key, all API tests will fail, to generate this key -# Log in to Twenty workspace, go to Settings > Developers, generate new key and paste it here -# In order to use it, header Authorization: Bearer token must be used -# This key works for both REST and GraphQL API -# API_DEV_KEY=fill_with_proper_key \ No newline at end of file +WEBSITE_URL=https://twenty.com \ No newline at end of file diff --git a/packages/twenty-e2e-testing/lib/fixtures/screenshot.ts b/packages/twenty-e2e-testing/lib/fixtures/screenshot.ts index abea94f61..39da746d2 100644 --- a/packages/twenty-e2e-testing/lib/fixtures/screenshot.ts +++ b/packages/twenty-e2e-testing/lib/fixtures/screenshot.ts @@ -25,7 +25,7 @@ export const test = base.extend<{ screenshotHook: void }>({ ), }); }, - { auto: true }, // automatic fixture runs with every test + { auto: true }, ], }); diff --git a/packages/twenty-e2e-testing/lib/pom/helper/insertFieldData.ts b/packages/twenty-e2e-testing/lib/pom/helper/insertFieldData.ts index a052eff68..19918511c 100644 --- a/packages/twenty-e2e-testing/lib/pom/helper/insertFieldData.ts +++ b/packages/twenty-e2e-testing/lib/pom/helper/insertFieldData.ts @@ -44,7 +44,7 @@ export class InsertFieldData { '//label[contains(., "POST CODE")]/../div[last()]/input', ); this.countrySelect = page.locator( - '//span[contains(., "COUNTRY")]/../div[last()]/input', + '//span[contains(., "COUNTRY")]/../div[last()]/div', ); this.arrayValueInput = page.locator("//input[@placeholder='Enter value']"); this.arrayAddValueButton = page.locator( diff --git a/packages/twenty-e2e-testing/lib/pom/helper/stripePage.ts b/packages/twenty-e2e-testing/lib/pom/helper/stripePage.ts index ccef759f9..ecbdb85a2 100644 --- a/packages/twenty-e2e-testing/lib/pom/helper/stripePage.ts +++ b/packages/twenty-e2e-testing/lib/pom/helper/stripePage.ts @@ -1,5 +1,55 @@ import { Locator, Page } from '@playwright/test'; export class StripePage { - // TODO: implement all necessary methods (staging/sandbox page - does it differ anyhow from normal page?) + private readonly cardNumberInput: Locator; + private readonly cardExpiryInput: Locator; + private readonly cardCvcInput: Locator; + private readonly cardholderNameInput: Locator; + private readonly startTrialButton: Locator; + private readonly cancelSubscriptionButton: Locator; + private readonly confirmButton: Locator; + private readonly returnToTwentyLink: Locator; + + constructor(public readonly page: Page) { + this.cardNumberInput = page.getByPlaceholder('1234 1234 1234 1234'); + this.cardExpiryInput = page.getByPlaceholder('MM / YY'); + this.cardCvcInput = page.getByPlaceholder('CVC'); + this.cardholderNameInput = page.getByPlaceholder('Full name on card'); + this.startTrialButton = page.getByTestId('hosted-payment-submit-button'); + this.cancelSubscriptionButton = page.locator( + 'a[data-test="cancel-subscription"]', + ); + this.confirmButton = page.getByTestId('confirm'); + this.returnToTwentyLink = page.getByTestId('return-to-business-link'); + } + + async fillCardNumber(number: string) { + await this.cardNumberInput.fill(number); + } + + async fillCardExpiry(expiry: string) { + await this.cardExpiryInput.fill(expiry); + } + + async fillCardCvc(cvc: string) { + await this.cardCvcInput.fill(cvc); + } + + async fillCardholderName(name: string) { + await this.cardholderNameInput.fill(name); + } + + async startTrial() { + await this.startTrialButton.click(); + } + + async clickCancelSubscription() { + await this.cancelSubscriptionButton.click(); + await this.confirmButton.click(); + await this.page.getByTestId('cancellation_reason_cancel').click(); + } + + async returnToTwenty() { + await this.returnToTwentyLink.click(); + } } diff --git a/packages/twenty-e2e-testing/lib/pom/settings/accountsSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/accountsSection.ts index 703cdffa6..1e29ddf5b 100644 --- a/packages/twenty-e2e-testing/lib/pom/settings/accountsSection.ts +++ b/packages/twenty-e2e-testing/lib/pom/settings/accountsSection.ts @@ -6,6 +6,7 @@ export class AccountsSection { private readonly addBlocklistField: Locator; private readonly addBlocklistButton: Locator; private readonly connectWithGoogleButton: Locator; + private readonly connectWithMicrosoftButton: Locator; constructor(public readonly page: Page) { this.page = page; @@ -22,6 +23,9 @@ export class AccountsSection { this.connectWithGoogleButton = page.getByRole('button', { name: 'Connect with Google', }); + this.connectWithMicrosoftButton = page.getByRole('button', { + name: 'Connect with Microsoft', + }); } async clickAddAccount() { @@ -51,4 +55,8 @@ export class AccountsSection { async linkGoogleAccount() { await this.connectWithGoogleButton.click(); } + + async linkMicrosoftAccount() { + await this.connectWithMicrosoftButton.click(); + } } diff --git a/packages/twenty-e2e-testing/lib/pom/settings/apisSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/apisSection.ts new file mode 100644 index 000000000..0c9bd79db --- /dev/null +++ b/packages/twenty-e2e-testing/lib/pom/settings/apisSection.ts @@ -0,0 +1,64 @@ +import { Locator, Page } from '@playwright/test'; + +export class APIsSection { + private readonly createAPIKeyButton: Locator; + private readonly regenerateAPIKeyButton: Locator; + private readonly nameOfAPIKeyInput: Locator; + private readonly expirationDateAPIKeySelect: Locator; + private readonly cancelButton: Locator; + private readonly saveButton: Locator; + private readonly deleteButton: Locator; + + constructor(public readonly page: Page) { + this.page = page; + this.createAPIKeyButton = page.getByRole('link', { + name: 'Create API Key', + }); + this.nameOfAPIKeyInput = page + .getByPlaceholder('E.g. backoffice integration') + .first(); + this.expirationDateAPIKeySelect = page.locator( + 'div[aria-controls="object-field-type-select-options"]', + ); + this.regenerateAPIKeyButton = page.getByRole('button', { + name: 'Regenerate Key', + }); + this.cancelButton = page.getByRole('button', { name: 'Cancel' }); + this.saveButton = page.getByRole('button', { name: 'Save' }); + this.deleteButton = page.getByRole('button', { name: 'Delete' }); + } + + async createAPIKey() { + await this.createAPIKeyButton.click(); + } + + async typeAPIKeyName(name: string) { + await this.nameOfAPIKeyInput.clear(); + await this.nameOfAPIKeyInput.fill(name); + } + + async selectAPIExpirationDate(date: string) { + await this.expirationDateAPIKeySelect.click(); + await this.page.getByText(date, { exact: true }).click(); + } + + async regenerateAPIKey() { + await this.regenerateAPIKeyButton.click(); + } + + async deleteAPIKey() { + await this.deleteButton.click(); + } + + async clickCancelButton() { + await this.cancelButton.click(); + } + + async clickSaveButton() { + await this.saveButton.click(); + } + + async checkAPIKeyDetails(name: string) { + await this.page.locator(`//a/div[contains(.,'${name}')][first()]`).click(); + } +} diff --git a/packages/twenty-e2e-testing/lib/pom/settings/developersSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/developersSection.ts deleted file mode 100644 index 0f7fec96f..000000000 --- a/packages/twenty-e2e-testing/lib/pom/settings/developersSection.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { Locator, Page } from '@playwright/test'; - -export class DevelopersSection { - private readonly readDocumentationButton: Locator; - private readonly createAPIKeyButton: Locator; - private readonly regenerateAPIKeyButton: Locator; - private readonly nameOfAPIKeyInput: Locator; - private readonly expirationDateAPIKeySelect: Locator; - private readonly createWebhookButton: Locator; - private readonly webhookURLInput: Locator; - private readonly webhookDescription: Locator; - private readonly webhookFilterObjectSelect: Locator; - private readonly webhookFilterActionSelect: Locator; - private readonly cancelButton: Locator; - private readonly saveButton: Locator; - private readonly deleteButton: Locator; - - constructor(public readonly page: Page) { - this.page = page; - this.readDocumentationButton = page.getByRole('link', { - name: 'Read documentation', - }); - this.createAPIKeyButton = page.getByRole('link', { - name: 'Create API Key', - }); - this.createWebhookButton = page.getByRole('link', { - name: 'Create Webhook', - }); - this.nameOfAPIKeyInput = page - .getByPlaceholder('E.g. backoffice integration') - .first(); - this.expirationDateAPIKeySelect = page - .locator('div') - .filter({ hasText: /^Never$/ }) - .nth(3); // good enough if expiration date will change only 1 time - this.regenerateAPIKeyButton = page.getByRole('button', { - name: 'Regenerate Key', - }); - this.webhookURLInput = page.getByPlaceholder('URL'); - this.webhookDescription = page.getByPlaceholder('Write a description'); - this.webhookFilterObjectSelect = page - .locator('div') - .filter({ hasText: /^All Objects$/ }) - .nth(3); // works only for first filter - this.webhookFilterActionSelect = page - .locator('div') - .filter({ hasText: /^All Actions$/ }) - .nth(3); // works only for first filter - this.cancelButton = page.getByRole('button', { name: 'Cancel' }); - this.saveButton = page.getByRole('button', { name: 'Save' }); - this.deleteButton = page.getByRole('button', { name: 'Delete' }); - } - - async openDocumentation() { - await this.readDocumentationButton.click(); - } - - async createAPIKey() { - await this.createAPIKeyButton.click(); - } - - async typeAPIKeyName(name: string) { - await this.nameOfAPIKeyInput.clear(); - await this.nameOfAPIKeyInput.fill(name); - } - - async selectAPIExpirationDate(date: string) { - await this.expirationDateAPIKeySelect.click(); - await this.page.getByText(date, { exact: true }).click(); - } - - async regenerateAPIKey() { - await this.regenerateAPIKeyButton.click(); - } - - async deleteAPIKey() { - await this.deleteButton.click(); - } - - async deleteWebhook() { - await this.deleteButton.click(); - } - - async createWebhook() { - await this.createWebhookButton.click(); - } - - async typeWebhookURL(url: string) { - await this.webhookURLInput.fill(url); - } - - async typeWebhookDescription(description: string) { - await this.webhookDescription.fill(description); - } - - async selectWebhookObject(object: string) { - // TODO: finish - } - - async selectWebhookAction(action: string) { - // TODO: finish - } - - async deleteWebhookFilter() { - // TODO: finish - } - - async clickCancelButton() { - await this.cancelButton.click(); - } - - async clickSaveButton() { - await this.saveButton.click(); - } - - async checkAPIKeyDetails(name: string) { - await this.page.locator(`//a/div[contains(.,'${name}')][first()]`).click(); - } - - async checkWebhookDetails(name: string) { - await this.page.locator(`//a/div[contains(.,'${name}')][first()]`).click(); - } -} diff --git a/packages/twenty-e2e-testing/lib/pom/settings/experienceSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/experienceSection.ts index 4ed6606c1..7949cce07 100644 --- a/packages/twenty-e2e-testing/lib/pom/settings/experienceSection.ts +++ b/packages/twenty-e2e-testing/lib/pom/settings/experienceSection.ts @@ -7,11 +7,12 @@ export class ExperienceSection { private readonly dateFormatDropdown: Locator; private readonly timeFormatDropdown: Locator; private readonly searchInput: Locator; + private readonly languageDropdown: Locator; constructor(public readonly page: Page) { this.page = page; - this.lightThemeButton = page.getByText('AaLight'); // it works - this.darkThemeButton = page.getByText('AaDark'); + this.lightThemeButton = page.locator('div[variant="Light"]').first(); + this.darkThemeButton = page.locator('div[variant="Dark"]').first(); this.timezoneDropdown = page.locator( '//span[contains(., "Time zone")]/../div/div/div', ); @@ -22,6 +23,9 @@ export class ExperienceSection { '//span[contains(., "Time format")]/../div/div/div', ); this.searchInput = page.getByPlaceholder('Search'); + this.languageDropdown = page.locator( + '//h2[contains(., "Language")]/../../../div/div/div', + ); } async changeThemeToLight() { @@ -52,4 +56,9 @@ export class ExperienceSection { await this.timeFormatDropdown.click(); await this.page.getByText(timeFormat, { exact: true }).click(); } + + async selectLanguage(language: string) { + await this.languageDropdown.click(); + await this.page.getByText(language, { exact: true }).click(); + } } diff --git a/packages/twenty-e2e-testing/lib/pom/settings/functionsSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/functionsSection.ts deleted file mode 100644 index f8f42418a..000000000 --- a/packages/twenty-e2e-testing/lib/pom/settings/functionsSection.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { Locator, Page } from '@playwright/test'; - -export class FunctionsSection { - private readonly newFunctionButton: Locator; - private readonly functionNameInput: Locator; - private readonly functionDescriptionInput: Locator; - private readonly editorTab: Locator; - private readonly codeEditorField: Locator; - private readonly resetButton: Locator; - private readonly publishButton: Locator; - private readonly testButton: Locator; - private readonly testTab: Locator; - private readonly runFunctionButton: Locator; - private readonly inputField: Locator; - private readonly settingsTab: Locator; - private readonly searchVariableInput: Locator; - private readonly addVariableButton: Locator; - private readonly nameVariableInput: Locator; - private readonly valueVariableInput: Locator; - private readonly cancelVariableButton: Locator; - private readonly saveVariableButton: Locator; - private readonly editVariableButton: Locator; - private readonly deleteVariableButton: Locator; - private readonly cancelButton: Locator; - private readonly saveButton: Locator; - private readonly deleteButton: Locator; - - constructor(public readonly page: Page) { - this.newFunctionButton = page.getByRole('button', { name: 'New Function' }); - this.functionNameInput = page.getByPlaceholder('Name'); - this.functionDescriptionInput = page.getByPlaceholder('Description'); - this.editorTab = page.getByTestId('tab-editor'); - this.codeEditorField = page.getByTestId('dummyInput'); // TODO: fix - this.resetButton = page.getByRole('button', { name: 'Reset' }); - this.publishButton = page.getByRole('button', { name: 'Publish' }); - this.testButton = page.getByRole('button', { name: 'Test' }); - this.testTab = page.getByTestId('tab-test'); - this.runFunctionButton = page.getByRole('button', { name: 'Run Function' }); - this.inputField = page.getByTestId('dummyInput'); // TODO: fix - this.settingsTab = page.getByTestId('tab-settings'); - this.searchVariableInput = page.getByPlaceholder('Search a variable'); - this.addVariableButton = page.getByRole('button', { name: 'Add Variable' }); - this.nameVariableInput = page.getByPlaceholder('Name').nth(1); - this.valueVariableInput = page.getByPlaceholder('Value'); - this.cancelVariableButton = page.locator('.css-uwqduk').first(); // TODO: fix - this.saveVariableButton = page.locator('.css-uwqduk').nth(1); // TODO: fix - this.editVariableButton = page.getByText('Edit', { exact: true }); - this.deleteVariableButton = page.getByText('Delete', { exact: true }); - this.cancelButton = page.getByRole('button', { name: 'Cancel' }); - this.saveButton = page.getByRole('button', { name: 'Save' }); - this.deleteButton = page.getByRole('button', { name: 'Delete function' }); - } - - async clickNewFunction() { - await this.newFunctionButton.click(); - } - - async typeFunctionName(name: string) { - await this.functionNameInput.fill(name); - } - - async typeFunctionDescription(description: string) { - await this.functionDescriptionInput.fill(description); - } - - async checkFunctionDetails(name: string) { - await this.page.getByRole('link', { name: `${name} nodejs18.x` }).click(); - } - - async clickEditorTab() { - await this.editorTab.click(); - } - - async clickResetButton() { - await this.resetButton.click(); - } - - async clickPublishButton() { - await this.publishButton.click(); - } - - async clickTestButton() { - await this.testButton.click(); - } - - async typeFunctionCode() { - // TODO: finish once utils are merged - } - - async clickTestTab() { - await this.testTab.click(); - } - - async runFunction() { - await this.runFunctionButton.click(); - } - - async typeFunctionInput() { - // TODO: finish once utils are merged - } - - async clickSettingsTab() { - await this.settingsTab.click(); - } - - async searchVariable(name: string) { - await this.searchVariableInput.fill(name); - } - - async addVariable() { - await this.addVariableButton.click(); - } - - async typeVariableName(name: string) { - await this.nameVariableInput.fill(name); - } - - async typeVariableValue(value: string) { - await this.valueVariableInput.fill(value); - } - - async editVariable(name: string) { - await this.page - .locator( - `//div[@data-testid='tooltip' and contains(., '${name}')]/../../div[last()]/div/div/button`, - ) - .click(); - await this.editVariableButton.click(); - } - - async deleteVariable(name: string) { - await this.page - .locator( - `//div[@data-testid='tooltip' and contains(., '${name}')]/../../div[last()]/div/div/button`, - ) - .click(); - await this.deleteVariableButton.click(); - } - - async cancelVariable() { - await this.cancelVariableButton.click(); - } - - async saveVariable() { - await this.saveVariableButton.click(); - } - - async clickCancelButton() { - await this.cancelButton.click(); - } - - async clickSaveButton() { - await this.saveButton.click(); - } - - async clickDeleteButton() { - await this.deleteButton.click(); - } -} diff --git a/packages/twenty-e2e-testing/lib/pom/settings/generalSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/generalSection.ts index d936a2e9e..a10e052c4 100644 --- a/packages/twenty-e2e-testing/lib/pom/settings/generalSection.ts +++ b/packages/twenty-e2e-testing/lib/pom/settings/generalSection.ts @@ -4,6 +4,8 @@ export class GeneralSection { private readonly workspaceNameField: Locator; private readonly supportSwitch: Locator; private readonly deleteWorkspaceButton: Locator; + private readonly customizeDomainButton: Locator; + private readonly subdomainInput: Locator; constructor(public readonly page: Page) { this.page = page; @@ -12,6 +14,12 @@ export class GeneralSection { this.deleteWorkspaceButton = page.getByRole('button', { name: 'Delete workspace', }); + this.customizeDomainButton = page.getByRole('button', { + name: 'Customize domain', + }); + this.subdomainInput = page.locator( + '//div[contains(.,".twenty-main.com")]/../input', + ); } async changeWorkspaceName(workspaceName: string) { @@ -26,4 +34,10 @@ export class GeneralSection { async clickDeleteWorkSpaceButton() { await this.deleteWorkspaceButton.click(); } + + async changeSubdomain(subdomain: string) { + await this.customizeDomainButton.click(); + await this.subdomainInput.fill(subdomain); + await this.page.getByRole('button', { name: 'Save' }).click(); + } } diff --git a/packages/twenty-e2e-testing/lib/pom/settings/newFieldSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/newFieldSection.ts index 50b37e03a..16fc12143 100644 --- a/packages/twenty-e2e-testing/lib/pom/settings/newFieldSection.ts +++ b/packages/twenty-e2e-testing/lib/pom/settings/newFieldSection.ts @@ -29,6 +29,7 @@ export class NewFieldSection { private readonly relationFieldLink: Locator; private readonly relationTypeSelect: Locator; private readonly objectDestinationSelect: Locator; + private readonly relationIconSelect: Locator; private readonly relationFieldNameInput: Locator; private readonly fullNameFieldLink: Locator; private readonly UUIDFieldLink: Locator; @@ -225,6 +226,11 @@ export class NewFieldSection { await this.page.getByTestId('tooltip').filter({ hasText: name }).click(); } + async selectRelationIcon(name: string) { + await this.relationIconSelect.click(); + await this.page.getByTitle(name).click(); + } + async typeRelationName(name: string) { await this.relationFieldNameInput.clear(); await this.relationFieldNameInput.fill(name); diff --git a/packages/twenty-e2e-testing/lib/pom/settings/rolesSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/rolesSection.ts new file mode 100644 index 000000000..7e76a717d --- /dev/null +++ b/packages/twenty-e2e-testing/lib/pom/settings/rolesSection.ts @@ -0,0 +1,22 @@ +import { Locator, Page } from '@playwright/test'; + +export class RolesSection { + private readonly page: Page; + private readonly createRoleButton: Locator; + private readonly defaultRoleDropdown: Locator; + + constructor(page: Page) { + this.page = page; + this.createRoleButton = page.getByRole('button', { name: 'Create Role' }); + this.defaultRoleDropdown = page.getByTestId('tooltip'); + } + + async clickCreateRoleButton() { + await this.createRoleButton.click(); + } + + async selectDefaultRole(role: string) { + await this.defaultRoleDropdown.click(); + await this.page.getByTestId('tooltip').getByText(role).click(); + } +} diff --git a/packages/twenty-e2e-testing/lib/pom/settings/securitySection.ts b/packages/twenty-e2e-testing/lib/pom/settings/securitySection.ts index 01b83b515..cbf97c1af 100644 --- a/packages/twenty-e2e-testing/lib/pom/settings/securitySection.ts +++ b/packages/twenty-e2e-testing/lib/pom/settings/securitySection.ts @@ -1,10 +1,28 @@ import { Locator, Page } from '@playwright/test'; export class SecuritySection { + private readonly googleToggle: Locator; + private readonly microsoftToggle: Locator; + private readonly passwordToggle: Locator; private readonly inviteByLinkToggle: Locator; constructor(public readonly page: Page) { - this.inviteByLinkToggle = page.locator('input[type="checkbox"]').nth(1); + this.googleToggle = page.getByLabel('Google'); + this.microsoftToggle = page.getByLabel('Microsoft'); + this.passwordToggle = page.getByLabel('Password'); + this.inviteByLinkToggle = page.getByLabel('Invite by Link'); + } + + async toggleGoogle() { + await this.googleToggle.click(); + } + + async toggleMicrosoft() { + await this.microsoftToggle.click(); + } + + async togglePassword() { + await this.passwordToggle.click(); } async toggleInviteByLink() { diff --git a/packages/twenty-e2e-testing/lib/pom/settings/webhooksSection.ts b/packages/twenty-e2e-testing/lib/pom/settings/webhooksSection.ts new file mode 100644 index 000000000..259591827 --- /dev/null +++ b/packages/twenty-e2e-testing/lib/pom/settings/webhooksSection.ts @@ -0,0 +1,65 @@ +import { Locator, Page } from '@playwright/test'; + +export class WebhooksSection { + private readonly createWebhookButton: Locator; + private readonly webhookURLInput: Locator; + private readonly webhookDescription: Locator; + private readonly deleteButton: Locator; + + constructor(public readonly page: Page) { + this.page = page; + this.createWebhookButton = page.getByRole('link', { + name: 'Create Webhook', + }); + this.webhookURLInput = page.getByPlaceholder('URL'); + this.webhookDescription = page.getByPlaceholder('Write a description'); + this.deleteButton = page.getByRole('button', { name: 'Delete' }); + } + + async deleteWebhook() { + await this.deleteButton.click(); + } + + async createWebhook() { + await this.createWebhookButton.click(); + } + + async typeWebhookURL(url: string) { + await this.webhookURLInput.clear(); + await this.webhookURLInput.fill(url); + } + + async typeWebhookDescription(description: string) { + await this.webhookDescription.fill(description); + } + + async selectWebhookObject(index: number, object: string) { + await this.page + .locator( + `//div[aria-controls="object-webhook-type-select-${index}-options"]`, + ) + .click(); + await this.page.getByRole('option').getByText(object).click(); + } + + async selectWebhookAction(index: number, action: string) { + await this.page + .locator( + `//div[aria-controls="operation-webhook-type-select-${index}-options"]`, + ) + .click(); + await this.page.getByRole('option').getByText(action).click(); + } + + async deleteWebhookFilter(index: number) { + await this.page + .locator( + `//div[aria-controls="object-webhook-type-select-${index}-options"]/../..//button`, + ) + .click(); + } + + async checkWebhookDetails(name: string) { + await this.page.locator(`//a/div[contains(.,'${name}')][first()]`).click(); + } +} diff --git a/packages/twenty-e2e-testing/lib/pom/settingsPage.ts b/packages/twenty-e2e-testing/lib/pom/settingsPage.ts index c753bb8d0..7098e6a6e 100644 --- a/packages/twenty-e2e-testing/lib/pom/settingsPage.ts +++ b/packages/twenty-e2e-testing/lib/pom/settingsPage.ts @@ -9,11 +9,14 @@ export class SettingsPage { private readonly calendarsLink: Locator; private readonly generalLink: Locator; private readonly membersLink: Locator; + private readonly rolesLink: Locator; private readonly dataModelLink: Locator; - private readonly developersLink: Locator; - private readonly functionsLink: Locator; - private readonly securityLink: Locator; private readonly integrationsLink: Locator; + private readonly securityLink: Locator; + private readonly apisLink: Locator; + private readonly webhooksLink: Locator; + private readonly adminPanelLink: Locator; + private readonly labLink: Locator; private readonly releasesLink: Locator; private readonly logoutLink: Locator; private readonly advancedToggle: Locator; @@ -28,11 +31,14 @@ export class SettingsPage { this.calendarsLink = page.getByRole('link', { name: 'Calendars' }); this.generalLink = page.getByRole('link', { name: 'General' }); this.membersLink = page.getByRole('link', { name: 'Members' }); + this.rolesLink = page.getByRole('link', { name: 'Roles' }); this.dataModelLink = page.getByRole('link', { name: 'Data model' }); - this.developersLink = page.getByRole('link', { name: 'Developers' }); - this.functionsLink = page.getByRole('link', { name: 'Functions' }); this.integrationsLink = page.getByRole('link', { name: 'Integrations' }); this.securityLink = page.getByRole('link', { name: 'Security' }); + this.apisLink = page.getByRole('link', { name: 'APIs' }); + this.webhooksLink = page.getByRole('link', { name: 'Webhooks' }); + this.adminPanelLink = page.getByRole('link', { name: 'Admin Panel' }); + this.labLink = page.getByRole('link', { name: 'Lab' }); this.releasesLink = page.getByRole('link', { name: 'Releases' }); this.logoutLink = page.getByText('Logout'); this.advancedToggle = page.locator('input[type="checkbox"]').first(); @@ -70,24 +76,36 @@ export class SettingsPage { await this.membersLink.click(); } + async goToRolesSection() { + await this.rolesLink.click(); + } + async goToDataModelSection() { await this.dataModelLink.click(); } - async goToDevelopersSection() { - await this.developersLink.click(); - } - - async goToFunctionsSection() { - await this.functionsLink.click(); + async goToIntegrationsSection() { + await this.integrationsLink.click(); } async goToSecuritySection() { await this.securityLink.click(); } - async goToIntegrationsSection() { - await this.integrationsLink.click(); + async goToAPIsSection() { + await this.apisLink.click(); + } + + async goToWebhooksSection() { + await this.webhooksLink.click(); + } + + async goToAdminPanelSection() { + await this.adminPanelLink.click(); + } + + async goToLabSection() { + await this.labLink.click(); } async goToReleasesIntegration() { diff --git a/packages/twenty-e2e-testing/package.json b/packages/twenty-e2e-testing/package.json index 5a3520247..3645c4484 100644 --- a/packages/twenty-e2e-testing/package.json +++ b/packages/twenty-e2e-testing/package.json @@ -6,6 +6,6 @@ "private": true, "license": "AGPL-3.0", "devDependencies": { - "@playwright/test": "^1.49.0" + "@playwright/test": "^1.51.0" } } diff --git a/yarn.lock b/yarn.lock index c797f9907..3475036e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11360,14 +11360,14 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:^1.49.0": - version: 1.49.1 - resolution: "@playwright/test@npm:1.49.1" +"@playwright/test@npm:^1.51.0": + version: 1.51.0 + resolution: "@playwright/test@npm:1.51.0" dependencies: - playwright: "npm:1.49.1" + playwright: "npm:1.51.0" bin: playwright: cli.js - checksum: 10c0/2fca0bb7b334f7a23c7c5dfa5dbe37b47794c56f39b747c8d74a2f95c339e7902a296f2f1dd32c47bdd723cfa92cee05219f1a5876725dc89a1871b9137a286d + checksum: 10c0/ae83dd2c3a32133de58f44a9dbcd73a8059155ebd8acc736ba8bd0a7ca99b194afe2e8f5a500861d18b1c8f06b4e4ea8de4a2402297c59053d4becc404b47e0a languageName: node linkType: hard @@ -44555,12 +44555,12 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.49.1": - version: 1.49.1 - resolution: "playwright-core@npm:1.49.1" +"playwright-core@npm:1.51.0": + version: 1.51.0 + resolution: "playwright-core@npm:1.51.0" bin: playwright-core: cli.js - checksum: 10c0/990b619c75715cd98b2c10c1180a126e3a454b247063b8352bc67792fe01183ec07f31d30c8714c3768cefed12886d1d64ac06da701f2baafc2cad9b439e3919 + checksum: 10c0/8f5de23088c5e97c00327f356b17e0223181e921baf99f4e38d9a3b18d0693db288f8b5389e96d0cb4a1b55f03870f140dd7346128a0c02ce36d11eb92153841 languageName: node linkType: hard @@ -44579,18 +44579,18 @@ __metadata: languageName: node linkType: hard -"playwright@npm:1.49.1": - version: 1.49.1 - resolution: "playwright@npm:1.49.1" +"playwright@npm:1.51.0": + version: 1.51.0 + resolution: "playwright@npm:1.51.0" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.49.1" + playwright-core: "npm:1.51.0" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10c0/2368762c898920d4a0a5788b153dead45f9c36c3f5cf4d2af5228d0b8ea65823e3bbe998877950a2b9bb23a211e4633996f854c6188769dc81a25543ac818ab5 + checksum: 10c0/e8509ea500e03e8051fd243f2347ac3196ff8dde4c20ae3aba4cf723e2b647a0158d209fba062995dab90590229a483d723562cf1ea8b2fc11698617027416fd languageName: node linkType: hard @@ -51273,7 +51273,7 @@ __metadata: version: 0.0.0-use.local resolution: "twenty-e2e-testing@workspace:packages/twenty-e2e-testing" dependencies: - "@playwright/test": "npm:^1.49.0" + "@playwright/test": "npm:^1.51.0" languageName: unknown linkType: soft