-
Notifications
You must be signed in to change notification settings - Fork 21
chore(components-angular, nextjs-integration): add general component e2e test suite #6471
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
Changes from all commits
Commits
Show all changes
92 commits
Select commit
Hold shift + click to select a range
aa1952f
added component-error-filter.ts
alionazherdetska 81b27e0
refactored component.cy
alionazherdetska 710ae7e
small refatcors
alionazherdetska e01ff4a
added the missing components to angular integration packages
alionazherdetska 7ceb237
small adjustemnts
alionazherdetska c14f405
small fixed for component-error-filter
alionazherdetska 6f380af
improved the code
alionazherdetska e6bcffd
reset some of the files
alionazherdetska dbda7d7
Merge branch 'main' into e2e-tabs-component-angular-nextjs
alionazherdetska ad9fd2f
chore(components-angular): add missing components markup to Angular iβ¦
alionazherdetska 83f0acc
added the header to the app
alionazherdetska 107c5eb
slight changes
alionazherdetska d0a0502
slight changes
alionazherdetska 72ce540
reverted redundant changes
alionazherdetska 372f242
reverted redundant changes
alionazherdetska 50b557f
removed Logo since it is present in the header
alionazherdetska 9c10643
avoided repetition
alionazherdetska 825f59d
small test fix
alionazherdetska c160588
removed redundant link from LinArea
alionazherdetska ddf40de
added the temporary workaround
alionazherdetska 7981ccf
Merge branch 'e2e-tabs-component-angular-nextjs' into add-missing-comβ¦
alionazherdetska b81692f
temp fix
alionazherdetska d506756
temp fix
alionazherdetska 421cb80
fix linting
alionazherdetska 2f48bcc
Merge branch 'e2e-tabs-component-angular-nextjs' into add-missing-comβ¦
alionazherdetska 4dac3aa
removed duplications
alionazherdetska e7a1fae
added comments
alionazherdetska 1d84773
removed duplications
alionazherdetska 8afc90e
reverted redundant changes
alionazherdetska 93c538a
reverted redundant changes
alionazherdetska 557b571
reset the files
alionazherdetska 2b3126d
reset the files
alionazherdetska b76c598
reset redundant changes
alionazherdetska 0c8b361
fixed the typos
alionazherdetska 1630c40
added the files
alionazherdetska d4c482a
Merge branch 'main' into e2e-tabs-component-angular-nextjs
alionazherdetska 5b0830a
reset the file
alionazherdetska 0ef7f61
Merge branch 'e2e-tabs-component-angular-nextjs' of https://github.coβ¦
alionazherdetska cdd3229
reset redundant changes
alionazherdetska 14d92e5
reverted the changes
alionazherdetska 7881907
temp fix
alionazherdetska b2e5e3e
fixed the error.tamplate
alionazherdetska f37a61f
added missing import
alionazherdetska 750629c
removed redundant import
alionazherdetska 81db496
small fixes
alionazherdetska 19d6873
fixed the naming
alionazherdetska 845234f
fixed console.error.filter
alionazherdetska 6a0e2dd
small fixes
alionazherdetska 36bb2a1
small fixes
alionazherdetska e3fbb8f
small changes
alionazherdetska 241e499
syncronized the error-filter files
alionazherdetska 092f29a
Merge branch 'main' into e2e-tabs-component-angular-nextjs
oliverschuerch 6126c9c
fixed sonar
alionazherdetska 8ad3a49
Merge branch 'e2e-tabs-component-angular-nextjs' of https://github.coβ¦
alionazherdetska eb3c295
Update packages/nextjs-integration/playwright/tests/ssr.spec.ts
alionazherdetska cd573a5
Update packages/nextjs-integration/playwright/tests/csr.spec.ts
alionazherdetska 5333e03
refactored `component.cy.ts`
alionazherdetska 5875647
Merge branch 'e2e-tabs-component-angular-nextjs' of https://github.coβ¦
alionazherdetska 6119051
Merge branch 'main' into e2e-tabs-component-angular-nextjs
alionazherdetska d96d02f
small fixes for the markup in ANgular package
alionazherdetska 70696ce
small refactor
alionazherdetska 5bff468
updated the header markup in nextjs witht the latest update
alionazherdetska 19dff69
tiny refactors
alionazherdetska 99e03b1
fix(component): fix TypeError for `post-stepper` component
alionazherdetska 8f50312
Merge branch '6682-bug-typeerror-cannot-read-properties-of-undefined-β¦
alionazherdetska ed0f17d
small changes
alionazherdetska b0bde1c
fix(component): added a changeset
alionazherdetska 7732596
removed the workaround
alionazherdetska a2c1785
refactored error-filters
alionazherdetska 33f3be5
removed redundant code
alionazherdetska 97e27fc
added fullyparallel locally
alionazherdetska 3a99b44
increased the number of workers
alionazherdetska d4b109b
try
alionazherdetska a7aedd3
reverted redundant changes
alionazherdetska 203f69a
removed redundant tests
alionazherdetska 8a84399
removed redundant code
alionazherdetska 5217279
possible fix
alionazherdetska a373435
added cypress e2e
alionazherdetska ac86fa7
temp fix
alionazherdetska aa8df87
fixed ssr file
alionazherdetska 7afa86d
small refactors
alionazherdetska c56b532
reverted redundant code
alionazherdetska a9db460
improved the naming
alionazherdetska 4a2fb77
improved the naming
alionazherdetska 04213f2
improved the naming
alionazherdetska 22cb7a7
Merge branch 'main' into e2e-tabs-component-angular-nextjs
alionazherdetska 0f3a015
chnaged the comment
alionazherdetska 48b3577
defined the stepItems in connectedCallback
alionazherdetska e81f23a
Merge branch '6682-bug-typeerror-cannot-read-properties-of-undefined-β¦
alionazherdetska 03e7080
Merge branch 'main' into e2e-tabs-component-angular-nextjs
alionazherdetska 0e86ec9
fixed the type
alionazherdetska 8425f8f
Merge branch 'e2e-tabs-component-angular-nextjs' of https://github.coβ¦
alionazherdetska File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 20 additions & 14 deletions
34
packages/components-angular/projects/consumer-app/cypress/e2e/components.cy.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,30 @@ | ||
| import * as Components from '@swisspost/design-system-components/dist'; | ||
| import { setupComponentErrorCapture, assertNoComponentErrors } from '../support/component-error-filter'; | ||
| import { componentNames } from '@swisspost/design-system-components/dist/component-names.json'; | ||
|
|
||
| const COMPONENT_TAG_NAMES = Object.keys(Components) | ||
| .filter(c => /^Post([A-Z][a-z]+)+$/.test(c)) | ||
| .map(c => c.replace(/([a-z0β9])([A-Z])/g, '$1-$2').toLowerCase()); | ||
|
|
||
| describe('Components', () => { | ||
| describe('components-angular (consumer-app)', () => { | ||
| beforeEach(() => { | ||
| cy.visit('/'); | ||
| cy.window().then(win => { | ||
| cy.wrap(cy.spy(win.console, 'error')).as('consoleError'); | ||
| }); | ||
|
|
||
| it('components-angular: should contain all components', () => { | ||
| componentNames.forEach(componentName => { | ||
| cy.get(componentName).first().should('exist'); | ||
| }); | ||
| }); | ||
|
|
||
| it('should not log any error', () => { | ||
| cy.get('@consoleError').should('not.have.been.called'); | ||
| it('components-angular: all components should be hydrated', () => { | ||
| componentNames.forEach(componentName => { | ||
| cy.get(componentName).first().should('have.class', 'hydrated'); | ||
| }); | ||
| }); | ||
|
|
||
| COMPONENT_TAG_NAMES.forEach(tagName => { | ||
| it(`should contain <${tagName}>`, () => { | ||
| cy.get(tagName).should('exist'); | ||
| it('components-angular: should not have console errors', () => { | ||
| const errorCapture = setupComponentErrorCapture(componentNames as string[]); | ||
|
|
||
| cy.visit('/', { | ||
| onBeforeLoad: errorCapture.onBeforeLoad | ||
| }); | ||
|
|
||
| assertNoComponentErrors(errorCapture.errors, componentNames as string[]); | ||
| }); | ||
| }); | ||
| }); |
129 changes: 129 additions & 0 deletions
129
packages/components-angular/projects/consumer-app/cypress/support/component-error-filter.ts
alionazherdetska marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| type CapturedError = { | ||
| message: string; | ||
| source: 'console' | 'error'; | ||
| stack?: string; | ||
| timestamp: number; | ||
| }; | ||
|
|
||
| /** | ||
| * Sets up error monitoring for specific components. | ||
| * Captures console.error and uncaught errors. | ||
| * | ||
| * @param componentNames - Array of component names to monitor for errors | ||
| * @returns Object containing: | ||
| * - errors: Live array of error messages (used by tests) | ||
| * - onBeforeLoad: Function to set up error capture on window before app loads | ||
| */ | ||
| export function setupComponentErrorCapture(componentNames: string[]) { | ||
| const errors: string[] = []; // live array used by tests | ||
| const captured: CapturedError[] = []; | ||
|
|
||
| // Pre-compute lowercase names to avoid repeated lowercasing in the hot path | ||
| const lowerCaseComponentNames = componentNames.map(n => n.toLowerCase()); | ||
|
|
||
| return { | ||
| errors, | ||
| captured, | ||
| onBeforeLoad | ||
| }; | ||
|
|
||
| /** | ||
| * Sets up error listeners on the application window before it loads. | ||
| * Intercepts console.error calls and window error events. | ||
| * | ||
| * @param win - Cypress AUT window object | ||
| */ | ||
| function onBeforeLoad(win: Cypress.AUTWindow): void { | ||
| // Store original console.error to call it after capturing | ||
| const originalError = win.console.error.bind(win.console); | ||
|
|
||
| // Intercept console.error() calls from the application | ||
| cy.stub(win.console, 'error').callsFake((...args: any[]) => { | ||
| originalError(...args); | ||
| // Convert all arguments to strings and join them | ||
| const message = args.map(extractMessage).join(' '); | ||
| pushError(message, 'console'); | ||
| }); | ||
|
|
||
| // Capture uncaught exceptions and runtime errors from the page | ||
| win.addEventListener('error', (e: ErrorEvent) => { | ||
| const message = e.message || extractMessage(e.error); | ||
| const stack = e.error?.stack; | ||
| pushError(message, 'error', stack); | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * Adds an error to the captured errors array if it passes all filters. | ||
| * Applies relevance checking. | ||
| * | ||
| * @param message - The error message to capture | ||
| * @param source - The source of the error ('console' or 'error') | ||
| * @param stack - Optional stack trace for the error | ||
| */ | ||
| function pushError(message: string, source: CapturedError['source'], stack?: string): void { | ||
| // Skip errors unrelated to our components | ||
| if (!isRelevant(message)) return; | ||
|
|
||
| const entry: CapturedError = { message, source, stack, timestamp: Date.now() }; | ||
| captured.push(entry); | ||
| errors.push(message); | ||
| } | ||
|
|
||
| /** | ||
| * Extracts a readable message from various error formats. | ||
| * Handles strings, Error objects, and other values gracefully. | ||
| * | ||
| * @param arg - Error object, string, or any value to extract message from | ||
| * @returns Extracted error message as a string | ||
| */ | ||
| function extractMessage(arg: unknown): string { | ||
| if (typeof arg === 'string') return arg; | ||
|
|
||
| // Handle Error-like objects | ||
| if (arg && typeof arg === 'object') { | ||
| if ('message' in arg && arg.message) { | ||
| return String(arg.message); | ||
| } | ||
| if ('stack' in arg && arg.stack) { | ||
| return String(arg.stack); | ||
| } | ||
| } | ||
|
|
||
| // Fallback: try to serialize or convert to string | ||
| try { | ||
| return JSON.stringify(arg); | ||
| } catch { | ||
| return String(arg); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Determines if an error message is relevant to the monitored components. | ||
| * An error is considered relevant if it mentions any of the component names. | ||
| * | ||
| * @param message - Error message to check for component relevance | ||
| * @returns True if the error mentions a monitored component, false otherwise | ||
| */ | ||
| function isRelevant(message: string): boolean { | ||
| const lower = message.toLowerCase(); | ||
| return lowerCaseComponentNames.some(n => lower.includes(n)); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Asserts that no component errors were captured during testing. | ||
| * Throws an error with detailed information if any errors were found. | ||
| * | ||
| * @param errors - Array of error messages captured during test execution | ||
| * @param componentNames - Array of component names that were monitored | ||
| * @throws Error if any errors were captured, with formatted error details | ||
| */ | ||
| export function assertNoComponentErrors(errors: string[], componentNames: string[]): void { | ||
| cy.then(() => { | ||
| if (errors.length === 0) return; | ||
|
|
||
| const list = errors.map((m, i) => `${i + 1}. ${m}`).join('\n'); | ||
| throw new Error(`Found ${errors.length} error(s) for [${componentNames.join(', ')}]:\n${list}`); | ||
| }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
packages/nextjs-integration/playwright/support/component-error-filter.ts
alionazherdetska marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| import { Page, ConsoleMessage } from '@playwright/test'; | ||
|
|
||
| const IGNORE_ERROR_PATTERNS = [ | ||
| /^hydration failed because/i, | ||
| /^server rendered html didn't match/i, | ||
| /^there was an error while hydrating/i, | ||
| /^hydration error/i, | ||
| /^a tree hydrated but/i, | ||
| ]; | ||
|
|
||
| type CapturedError = { | ||
| message: string; | ||
| source: 'console'; | ||
| stack?: string; | ||
| timestamp: number; | ||
| }; | ||
|
|
||
| /** | ||
| * Sets up error monitoring for specific components. | ||
| * Captures console.error messages. | ||
| * Excludes known hydration errors (SSR-specific). | ||
| * | ||
| * @param page - Playwright page object to monitor | ||
| * @param componentNames - Array of component names to monitor for errors | ||
| * @returns Object containing: | ||
| * - errors: Live array of error messages (used by tests) | ||
| * - captured: Array of detailed error objects with metadata | ||
| * - dispose: Function to clean up event listeners | ||
| */ | ||
| export function setupComponentErrorCapture(page: Page, componentNames: string[]) { | ||
| const errors: string[] = []; // live array used by tests | ||
| const captured: CapturedError[] = []; | ||
|
|
||
| // Pre-compute lowercase names to avoid repeated lowercasing in the hot path | ||
| const lowerCaseComponentNames = componentNames.map(n => n.toLowerCase()); | ||
|
|
||
| page.on('console', onConsole); | ||
|
|
||
| return { errors, dispose, captured } as const; | ||
|
|
||
| /** | ||
| * Event handler for console messages from the page. | ||
| * Captures console.error messages and passes them to pushError. | ||
| * | ||
| * @param msg - Playwright ConsoleMessage object | ||
| */ | ||
| function onConsole(msg: ConsoleMessage): void { | ||
| try { | ||
| if (msg.type() === 'error') { | ||
| pushError(msg.text(), 'console'); | ||
| } | ||
| } catch { | ||
| // ignore handler errors to prevent test interference | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Adds an error to the captured errors array if it passes all filters. | ||
| * Applies relevance checking and ignore pattern filtering. | ||
| * | ||
| * @param message - The error message to capture | ||
| * @param source - The source of the error ('console') | ||
| * @param stack - Optional stack trace for the error | ||
| */ | ||
| function pushError(message: string, source: CapturedError['source'], stack?: string): void { | ||
| // Skip hydration errors and errors unrelated to our components | ||
| if (isIgnoredError(message) || !isRelevant(message)) return; | ||
|
|
||
| const entry: CapturedError = { message, source, stack, timestamp: Date.now() }; | ||
| captured.push(entry); | ||
| errors.push(message); | ||
| } | ||
|
|
||
| /** | ||
| * Checks if an error message matches known patterns that should be ignored. | ||
| * Currently filters out hydration-related errors and other non-critical messages. | ||
| * | ||
| * @param text - Error message to check against ignore patterns | ||
| * @returns True if the error should be ignored, false otherwise | ||
| */ | ||
| function isIgnoredError(text: string): boolean { | ||
| // Check if error message matches any known hydration/non-critical patterns | ||
| return IGNORE_ERROR_PATTERNS.some(pattern => pattern.test(text)); | ||
| } | ||
|
|
||
| /** | ||
| * Determines if an error message is relevant to the monitored components. | ||
| * An error is considered relevant if it mentions any of the component names. | ||
| * | ||
| * @param message - Error message to check for component relevance | ||
| * @returns True if the error mentions a monitored component, false otherwise | ||
| */ | ||
| function isRelevant(message: string): boolean { | ||
| const lower = message.toLowerCase(); | ||
| return lowerCaseComponentNames.some(n => lower.includes(n)); | ||
| } | ||
|
|
||
| /** | ||
| * Removes event listeners and cleans up resources. | ||
| * Should be called after tests complete to prevent memory leaks. | ||
| * Safe to call multiple times. | ||
| */ | ||
| function dispose(): void { | ||
| try { | ||
| page.off('console', onConsole); | ||
| } catch { | ||
| // best-effort teardown - don't throw during cleanup | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Asserts that no component errors were captured during testing. | ||
| * Throws an error with detailed information if any errors were found. | ||
| * | ||
| * @param errors - Array of error messages captured during test execution | ||
| * @param componentNames - Array of component names that were monitored | ||
| * @throws Error if any errors were captured, with formatted error details | ||
| */ | ||
| export function assertNoComponentErrors(errors: string[], componentNames: string[]): void { | ||
| if (errors.length === 0) return; | ||
|
|
||
| const list = errors.map((m, i) => `${i + 1}. ${m}`).join('\n'); | ||
| throw new Error(`Found ${errors.length} error(s) for [${componentNames.join(', ')}]:\n${list}`); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the CI runs both components and components-angular suites in the same pipeline, test suite and test names are now explicit (prefixed with
components-angular) to avoid ambiguous logs when both suites appear in CI.