Compare commits
2
Commits
843c51dd91
...
b82b989cc8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b82b989cc8 | ||
|
|
c2ee0b0c5d |
@@ -25,14 +25,18 @@ test.describe('Editing the customer emails', () => {
|
||||
'Favorited item sold',
|
||||
'Favorited item withdrawn',
|
||||
'Cart reminder',
|
||||
'Email address changed'
|
||||
'Email address changed',
|
||||
// Added in #337, and the reason these are matched on the whole
|
||||
// accessible name rather than as substrings: it extends the label above
|
||||
// it, so an unanchored match resolved to both tabs.
|
||||
'Email address changed by the shop'
|
||||
]) {
|
||||
await expect(adminEmails.railTab(new RegExp(label))).toBeVisible();
|
||||
await expect(adminEmails.railTab(label)).toBeVisible();
|
||||
}
|
||||
|
||||
// Only a customised template is marked, so which ones have been changed is
|
||||
// visible without opening each one. An untouched template carries nothing.
|
||||
await expect(adminEmails.railTab(/Password reset/)).toBeVisible();
|
||||
await expect(adminEmails.railTab('Password reset')).toBeVisible();
|
||||
await expect(adminEmails.customisedTab('Password reset')).toHaveCount(0);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
import { FrameLocator, Locator, Page, expect } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* A matcher for one template label, against a tab's *whole* accessible name.
|
||||
*
|
||||
* A tab is named for its template, plus the word "Customised" once it has been
|
||||
* edited — the dot beside it carries that as an aria-label, so the state is not
|
||||
* colour-only.
|
||||
*
|
||||
* Anchored at both ends, which is the entire point of this function. The
|
||||
* locators here used to build an unanchored regex from the label, so a template
|
||||
* whose name merely *began* with another's matched both. Adding "Email address
|
||||
* changed by the shop" alongside "Email address changed" broke a passing test
|
||||
* with a strict-mode violation naming the assertion rather than the new
|
||||
* template — the same shape as the switch locator that silently retargeted in
|
||||
* #317, and the same cost to diagnose.
|
||||
*
|
||||
* The escape matters for the same reason: these labels are copy, and copy
|
||||
* acquires brackets and full stops eventually.
|
||||
*/
|
||||
function nameMatching(label: string, options: { customised?: boolean } = {}): RegExp {
|
||||
const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const suffix = options.customised ? '\\s+Customised' : '(?:\\s+Customised)?';
|
||||
return new RegExp(`^${escaped}${suffix}$`);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Emails tab: a vertical rail of template types and one editor at a time.
|
||||
*
|
||||
@@ -30,13 +54,30 @@ export class AdminEmails {
|
||||
return this.page.getByRole('button', { name: `Insert {{${name}}}` });
|
||||
}
|
||||
|
||||
/** One template's entry in the rail. */
|
||||
railTab(label: string | RegExp): Locator {
|
||||
return this.page.getByRole('tab', { name: label });
|
||||
/**
|
||||
* One template's entry in the rail, matched on its whole accessible name.
|
||||
*
|
||||
* A tab's accessible name is the template's label, plus the word "Customised"
|
||||
* when it has been edited — the dot beside it carries that as an aria-label so
|
||||
* the state is not colour-only.
|
||||
*
|
||||
* Anchored at both ends, which is the point of this helper rather than a bare
|
||||
* substring match. These locators used to build an unanchored regex from the
|
||||
* label, so a template whose name merely *began* with another's matched both.
|
||||
* Adding "Email address changed by the shop" beside "Email address changed"
|
||||
* broke a passing test with a strict-mode violation, and the failure named the
|
||||
* assertion rather than the new template — the same shape as the switch
|
||||
* locator that silently retargeted in #317.
|
||||
*
|
||||
* The escape matters for the same reason: a label is copy, and copy acquires
|
||||
* brackets and full stops eventually.
|
||||
*/
|
||||
railTab(label: string): Locator {
|
||||
return this.page.getByRole('tab', { name: nameMatching(label) });
|
||||
}
|
||||
|
||||
customisedTab(label: string): Locator {
|
||||
return this.page.getByRole('tab', { name: new RegExp(`${label}.*Customised`) });
|
||||
return this.page.getByRole('tab', { name: nameMatching(label, { customised: true }) });
|
||||
}
|
||||
|
||||
subject(label: string): Locator {
|
||||
@@ -65,7 +106,7 @@ export class AdminEmails {
|
||||
* resolved mid-swap finds the outgoing one.
|
||||
*/
|
||||
async openTemplate(label: string): Promise<void> {
|
||||
await this.railTab(new RegExp(label)).click();
|
||||
await this.railTab(label).click();
|
||||
await expect(this.subject(label)).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user