From 91378f7381869caf19c01c7ee9763892b8efe48e Mon Sep 17 00:00:00 2001 From: Alex Tkachev Date: Mon, 17 Feb 2025 18:14:44 +0400 Subject: [PATCH] test: move silverback-iframe tests to template --- .../593298cc-d7c6-4a3a-a1af-3649e521067c.yml | 58 +++++ .../for_testing_confirmation_options.yml | 204 ++++++++++++++++++ tests/e2e/fixtures.ts | 16 ++ tests/e2e/helpers/drupal.ts | 17 ++ tests/e2e/specs/drupal/login.spec.ts | 6 +- .../specs/drupal/silverback-iframe.spec.ts | 202 +++++++++++++++++ tests/e2e/specs/setup.ts | 3 + 7 files changed, 503 insertions(+), 3 deletions(-) create mode 100644 packages/drupal/test_content/content/node/593298cc-d7c6-4a3a-a1af-3649e521067c.yml create mode 100644 packages/drupal/test_content/webforms/for_testing_confirmation_options.yml create mode 100644 tests/e2e/fixtures.ts create mode 100644 tests/e2e/helpers/drupal.ts create mode 100644 tests/e2e/specs/drupal/silverback-iframe.spec.ts diff --git a/packages/drupal/test_content/content/node/593298cc-d7c6-4a3a-a1af-3649e521067c.yml b/packages/drupal/test_content/content/node/593298cc-d7c6-4a3a-a1af-3649e521067c.yml new file mode 100644 index 000000000..920d1c5b4 --- /dev/null +++ b/packages/drupal/test_content/content/node/593298cc-d7c6-4a3a-a1af-3649e521067c.yml @@ -0,0 +1,58 @@ +_meta: + version: '1.0' + entity_type: node + uuid: 593298cc-d7c6-4a3a-a1af-3649e521067c + bundle: page + default_langcode: en +default: + revision_uid: + - + target_id: 1 + status: + - + value: true + uid: + - + target_id: 1 + title: + - + value: 'Test webform confirmation options' + created: + - + value: 1739788850 + promote: + - + value: false + sticky: + - + value: false + moderation_state: + - + value: published + pate_is_template: + - + value: false + pate_structure_only: + - + value: false + path: + - + alias: /test-webform-confirmation-options + langcode: en + pathauto: 0 + content_translation_source: + - + value: und + content_translation_outdated: + - + value: false + body: + - + value: |- + + + + + + format: gutenberg + summary: '' diff --git a/packages/drupal/test_content/webforms/for_testing_confirmation_options.yml b/packages/drupal/test_content/webforms/for_testing_confirmation_options.yml new file mode 100644 index 000000000..fae1b2a1e --- /dev/null +++ b/packages/drupal/test_content/webforms/for_testing_confirmation_options.yml @@ -0,0 +1,204 @@ +uuid: 452a69f0-cade-443f-8ba6-46b5fe92cedd +langcode: en +status: open +dependencies: { } +weight: 0 +open: null +close: null +uid: 1 +template: false +archive: false +id: for_testing_confirmation_options +title: 'For testing confirmation options' +description: '' +categories: { } +elements: |- + optional_text_field: + '#type': textfield + '#title': 'Optional text field' + '#description': 'A link to article with "iframe=true".' +css: '' +javascript: '' +settings: + ajax: false + ajax_scroll_top: form + ajax_progress_type: '' + ajax_effect: '' + ajax_speed: null + page: true + page_submit_path: '' + page_confirm_path: '' + page_theme_name: '' + form_title: both + form_submit_once: false + form_open_message: '' + form_close_message: '' + form_exception_message: '' + form_previous_submissions: true + form_confidential: false + form_confidential_message: '' + form_disable_remote_addr: false + form_convert_anonymous: false + form_prepopulate: false + form_prepopulate_source_entity: false + form_prepopulate_source_entity_required: false + form_prepopulate_source_entity_type: '' + form_unsaved: false + form_disable_back: false + form_submit_back: false + form_disable_autocomplete: false + form_novalidate: false + form_disable_inline_errors: false + form_required: false + form_autofocus: false + form_details_toggle: false + form_reset: false + form_access_denied: default + form_access_denied_title: '' + form_access_denied_message: '' + form_access_denied_attributes: { } + form_file_limit: '' + form_attributes: { } + form_method: '' + form_action: '' + share: false + share_node: false + share_theme_name: '' + share_title: true + share_page_body_attributes: { } + submission_label: '' + submission_exception_message: '' + submission_locked_message: '' + submission_log: false + submission_excluded_elements: { } + submission_exclude_empty: false + submission_exclude_empty_checkbox: false + submission_views: { } + submission_views_replace: { } + submission_user_columns: { } + submission_user_duplicate: false + submission_access_denied: default + submission_access_denied_title: '' + submission_access_denied_message: '' + submission_access_denied_attributes: { } + previous_submission_message: '' + previous_submissions_message: '' + autofill: false + autofill_message: '' + autofill_excluded_elements: { } + wizard_progress_bar: true + wizard_progress_pages: false + wizard_progress_percentage: false + wizard_progress_link: false + wizard_progress_states: false + wizard_start_label: '' + wizard_preview_link: false + wizard_confirmation: true + wizard_confirmation_label: '' + wizard_auto_forward: true + wizard_auto_forward_hide_next_button: false + wizard_keyboard: true + wizard_track: '' + wizard_prev_button_label: '' + wizard_next_button_label: '' + wizard_toggle: false + wizard_toggle_show_label: '' + wizard_toggle_hide_label: '' + wizard_page_type: container + wizard_page_title_tag: h2 + preview: 0 + preview_label: '' + preview_title: '' + preview_message: '' + preview_attributes: { } + preview_excluded_elements: { } + preview_exclude_empty: true + preview_exclude_empty_checkbox: false + draft: none + draft_multiple: false + draft_auto_save: false + draft_saved_message: '' + draft_loaded_message: '' + draft_pending_single_message: '' + draft_pending_multiple_message: '' + confirmation_type: page + confirmation_url: '' + confirmation_title: '' + confirmation_message: '' + confirmation_attributes: { } + confirmation_back: true + confirmation_back_label: '' + confirmation_back_attributes: { } + confirmation_exclude_query: false + confirmation_exclude_token: false + confirmation_update: false + limit_total: null + limit_total_interval: null + limit_total_message: '' + limit_total_unique: false + limit_user: null + limit_user_interval: null + limit_user_message: '' + limit_user_unique: false + entity_limit_total: null + entity_limit_total_interval: null + entity_limit_user: null + entity_limit_user_interval: null + purge: none + purge_days: null + results_disabled: false + results_disabled_ignore: false + results_customize: false + token_view: false + token_update: false + token_delete: false + serial_disabled: false +access: + create: + roles: + - anonymous + - authenticated + users: { } + permissions: { } + view_any: + roles: { } + users: { } + permissions: { } + update_any: + roles: { } + users: { } + permissions: { } + delete_any: + roles: { } + users: { } + permissions: { } + purge_any: + roles: { } + users: { } + permissions: { } + view_own: + roles: { } + users: { } + permissions: { } + update_own: + roles: { } + users: { } + permissions: { } + delete_own: + roles: { } + users: { } + permissions: { } + administer: + roles: { } + users: { } + permissions: { } + test: + roles: { } + users: { } + permissions: { } + configuration: + roles: { } + users: { } + permissions: { } +handlers: { } +variants: { } \ No newline at end of file diff --git a/tests/e2e/fixtures.ts b/tests/e2e/fixtures.ts new file mode 100644 index 000000000..1eecd3d4c --- /dev/null +++ b/tests/e2e/fixtures.ts @@ -0,0 +1,16 @@ +import { Page, test as base } from '@playwright/test'; + +type Fixtures = { + pageAdmin: Page; +}; + +export const test = base.extend({ + pageAdmin: async ({ browser }, use) => { + const context = await browser.newContext({ + storageState: '.auth/admin.json', + }); + const page = await context.newPage(); + await use(page); + await context.close(); + }, +}); diff --git a/tests/e2e/helpers/drupal.ts b/tests/e2e/helpers/drupal.ts new file mode 100644 index 000000000..c15f0e6b4 --- /dev/null +++ b/tests/e2e/helpers/drupal.ts @@ -0,0 +1,17 @@ +import { execSync } from 'child_process'; + +export const drush = (cmd: string): string => { + return execSync( + `pnpm --filter "@custom/cms" exec -- pnpm --silent drush ${cmd}`, + ).toString(); +}; + +export const silverback = (cmd: string): string => { + return execSync( + `pnpm --filter "@custom/cms" exec -- pnpm --silent silverback ${cmd}`, + ).toString(); +}; + +export const resetDrupal = () => { + silverback('-y snapshot-restore tests-initial'); +}; diff --git a/tests/e2e/specs/drupal/login.spec.ts b/tests/e2e/specs/drupal/login.spec.ts index 085781977..4580f3c05 100644 --- a/tests/e2e/specs/drupal/login.spec.ts +++ b/tests/e2e/specs/drupal/login.spec.ts @@ -1,10 +1,10 @@ -import { expect, test } from '@playwright/test'; +import { expect } from '@playwright/test'; +import { test } from '../../fixtures'; import { cmsUrl } from '../../helpers/url'; test.describe('authentication', () => { - test.use({ storageState: '.auth/admin.json' }); - test('login form', async ({ page }) => { + test('login form', async ({ pageAdmin: page }) => { await page.goto(cmsUrl('/user')); await expect( page.getByRole('heading', { name: 'admin', exact: true }), diff --git a/tests/e2e/specs/drupal/silverback-iframe.spec.ts b/tests/e2e/specs/drupal/silverback-iframe.spec.ts new file mode 100644 index 000000000..9666ae5a8 --- /dev/null +++ b/tests/e2e/specs/drupal/silverback-iframe.spec.ts @@ -0,0 +1,202 @@ +import { expect, Frame, PlaywrightTestArgs } from '@playwright/test'; + +import { test } from '../../fixtures'; +import { drush, resetDrupal } from '../../helpers/drupal'; +import { cmsUrl, websiteUrl } from '../../helpers/url'; + +test.beforeEach(() => { + resetDrupal(); +}); +test.afterAll(() => { + resetDrupal(); +}); + +test('the unsupported confirmation type is replaced with the default value', async ({ + pageAdmin: page, +}) => { + const result = drush( + `cget webform.webform.for_testing_confirmation_options settings.confirmation_type --include-overridden --format=json`, + ); + const confirmationType = Object.values(JSON.parse(result))[0]; + expect(confirmationType).toEqual('page'); + + await page.goto( + cmsUrl( + `/en/admin/structure/webform/manage/for_testing_confirmation_options/settings/confirmation`, + ), + ); + await expect( + page.locator('input[name="confirmation_type"][value="inline"]'), + ).toBeChecked(); +}); + +test('only allowed confirmation types are listed in the webform config', async ({ + pageAdmin: page, +}) => { + const getOptions = async () => { + await page.goto( + cmsUrl( + `/en/admin/structure/webform/manage/for_testing_confirmation_options/settings/confirmation`, + ), + ); + return Promise.all( + (await page.$$('input[name="confirmation_type"]')).map((option) => + option.getAttribute('value'), + ), + ); + }; + + // Case: limit_webform_confirmation_options is FALSE. + // Can't use "drush cset" due to https://github.com/drush-ops/drush/issues/3793 + // TODO: asd + drush( + `eval '\\Drupal::configFactory()->getEditable("silverback_iframe.settings")->set("limit_webform_confirmation_options", FALSE)->save();'`, + ); + expect(await getOptions()).not.toEqual(confirmationOptions); + + // Case: limit_webform_confirmation_options is TRUE. + drush( + `-y cset silverback_iframe.settings limit_webform_confirmation_options true --input-format=yaml`, + ); + expect(await getOptions()).toEqual(confirmationOptions); + + // Case: limit_webform_confirmation_options is missing. + drush(`-y cdel silverback_iframe.settings`); + expect(await getOptions()).toEqual(confirmationOptions); +}); + +test('confirmation type: inline', async ({ page, pageAdmin }) => { + await setConfirmationOption(pageAdmin, 'inline', { addMessage: true }); + await submitWebform(page); + + await expect(page.getByText('Test message with some text.')).toBeVisible(); + expect(await page.$('iframe')).toBeNull(); +}); + +test('confirmation type: message', async ({ page, pageAdmin }) => { + await setConfirmationOption(pageAdmin, 'message', { addMessage: true }); + await submitWebform(page); + + await expect(page.getByText('Test message with some text.')).toBeVisible(); + expect(await page.$('iframe')).not.toBeNull(); +}); + +test('confirmation type: url', async ({ page, pageAdmin }) => { + await setConfirmationOption(pageAdmin, 'url', { + setRedirectUrl: '/en/article/with-everything', + }); + await submitWebform(page); + await page.waitForURL(/\/en\/article\/with-everything/); + + // It's important to ensure that we are redirected to Gatsby, not to Drupal. + expect(page.url()).toContain(websiteUrl('')); +}); + +test('confirmation type: url_message', async ({ page, pageAdmin }) => { + await setConfirmationOption(pageAdmin, 'url_message', { + addMessage: true, + setRedirectUrl: '/en/article/other', + }); + await submitWebform(page); + await page.waitForURL(/\/en\/article\/other/); + + await expect(page.getByText('Test message with some text.')).toBeVisible(); + // It's important to ensure that we are redirected to Gatsby, not to Drupal. + expect(page.url()).toContain(websiteUrl('')); +}); + +test('confirmation type: none', async ({ page, pageAdmin }) => { + await setConfirmationOption(pageAdmin, 'none'); + await submitWebform(page); + + await expect(page.locator('iframe')).toHaveCount(1); + expect( + (await page.locator('.silverback-iframe-messages').textContent())?.trim(), + ).toBeFalsy(); +}); + +test('confirmation type: message with fallback', async ({ + page, + pageAdmin, +}) => { + await setConfirmationOption(pageAdmin, 'message', { + addMessage: + '
You will be redirected back to the form.
', + }); + await submitWebform(page); + + await expect( + page.getByText('The contact form has been submitted'), + ).toBeVisible(); + expect(page.url()).toBe( + // It's important to ensure that we are redirected to Gatsby, not to + // Drupal. + websiteUrl('/en/webform/success'), + ); +}); + +const confirmationOptions = [ + 'inline', + 'message', + 'url', + 'url_message', + 'none', +] as const; +type ConfirmationOption = (typeof confirmationOptions)[number]; + +const setConfirmationOption = async ( + page: PlaywrightTestArgs['page'], + confirmationOption: ConfirmationOption, + options?: { + addMessage?: boolean | string; + setRedirectUrl?: string; + }, +) => { + await page.goto( + cmsUrl( + `/en/admin/structure/webform/manage/for_testing_confirmation_options/settings/confirmation`, + ), + ); + + await page.click( + `input[name="confirmation_type"][value="${confirmationOption}"]`, + ); + + if (options?.addMessage === true) { + await page + .getByRole('textbox', { name: 'Confirmation message' }) + .fill('Test message with some text.'); + } + if (typeof options?.addMessage === 'string') { + await page + .getByRole('textbox', { name: 'Confirmation message' }) + .fill(options.addMessage); + } + + if (options?.setRedirectUrl) { + await page.fill('input[name=confirmation_url]', options.setRedirectUrl); + } + + await page.getByRole('button', { name: 'Save', exact: true }).click(); +}; + +const submitWebform = async (page: PlaywrightTestArgs['page']) => { + await page.goto(websiteUrl('/en/test-webform-confirmation-options')); + const iframe = await getIframe(page); + await iframe.getByRole('button', { name: 'Submit' }).click(); +}; + +export const getIframe = async ( + page: PlaywrightTestArgs['page'], +): Promise => { + await page.waitForSelector('iframe'); + const iframe = await page.$('iframe'); + if (!iframe) { + throw new Error('Cannot get iframe.'); + } + const frame = await iframe.contentFrame(); + if (!frame) { + throw new Error("Cannot get iframe's content frame."); + } + return frame; +}; diff --git a/tests/e2e/specs/setup.ts b/tests/e2e/specs/setup.ts index 1480e8b67..86b3f5f9f 100644 --- a/tests/e2e/specs/setup.ts +++ b/tests/e2e/specs/setup.ts @@ -1,5 +1,6 @@ import { expect, test as setup } from '@playwright/test'; +import { silverback } from '../helpers/drupal'; import { cmsUrl } from '../helpers/url'; import { netlifyBootTimeout, @@ -19,4 +20,6 @@ setup('setup', async ({ page }) => { page.getByRole('heading', { name: 'admin', exact: true }), ).toHaveCount(1); await page.context().storageState({ path: '.auth/admin.json' }); + + silverback('-y snapshot-create tests-initial'); });