Skip to content

Commit

Permalink
refactor(e2e): use web-first assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
sjinks committed Mar 12, 2024
1 parent 1fb52bd commit c6fd212
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 20 deletions.
20 changes: 14 additions & 6 deletions assets/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ jQuery(($) => {
const message = e instanceof DOMException ? decodeDOMException(e, false) : e.message;
const table = parent.find('.registered-keys');
table.siblings('.notice').remove();
table.before('<div class="notice notice-error inline" role="alert"><p>' + message + '</p></div>');
table.before(
'<div class="tfa-webauthn-alert notice notice-error inline" role="alert"><p>' + message + '</p></div>',
);
}

function startRegistration() {
Expand Down Expand Up @@ -128,7 +130,9 @@ jQuery(($) => {
table.find('tbody > tr:last-child').after(response.data.row);
table.find('tbody > tr.no-items').remove();
table.before(
'<div class="notice notice-success inline" role="alert"><p>' + L_KEY_REGISTERED + '</p></div>',
'<div class="tfa-webauthn-alert notice notice-success inline" role="alert"><p>' +
L_KEY_REGISTERED +
'</p></div>',
);
})
.catch(errorHandler)
Expand Down Expand Up @@ -163,15 +167,17 @@ jQuery(($) => {
.on('click', '.button-link-delete', () => {
actions.siblings('.confirm-revoke').hide();
updateStatus(L_SENDING_REQUEST);
return ajaxRequest<unknown>({
ajaxRequest<unknown>({
action: 'webauthn_delete_key',
_ajax_nonce: nonce,
user_id: $('#user_id').val(),
handle,
})
.then(() => {
table.before(
'<div class="notice notice-success inline" role="alert"><p>' + L_KEY_REVOKED + '</p></div>',
'<div class="tfa-webauthn-alert notice notice-success inline" role="alert"><p>' +
L_KEY_REVOKED +
'</p></div>',
);
a.closest('tr').remove();
if (!table.find('tbody > tr').length) {
Expand Down Expand Up @@ -211,7 +217,7 @@ jQuery(($) => {
const keyname = actions.siblings('.rename-key').find('input[type="text"]').val() as string;
actions.siblings('.rename-key').hide();
updateStatus(L_SENDING_REQUEST);
return ajaxRequest<RenameResponse>({
ajaxRequest<RenameResponse>({
action: 'webauthn_rename_key',
_ajax_nonce: nonce,
user_id: $('#user_id').val(),
Expand All @@ -220,7 +226,9 @@ jQuery(($) => {
})
.then((r) => {
table.before(
'<div class="notice notice-success inline" role="alert"><p>' + L_KEY_RENAMED + '</p></div>',
'<div class="tfa-webauthn-alert notice notice-success inline" role="alert"><p>' +
L_KEY_RENAMED +
'</p></div>',
);

a.closest('td').find('span.key-name').text(r.data.name);
Expand Down
18 changes: 8 additions & 10 deletions tests/e2e/lib/profilepage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const waSelectors = {
registerNewKeyButton: 'div.add-webauthn-key > p > button',
keyActions: (credentialId: string) => `table.webauthn-keys > tbody td.name:has(a[data-handle="${credentialId}"])`,
noItemsRow: 'table.webauthn-keys > tbody > tr.no-items',
operationStatus: (text: string) => `div[role="alert"] > p:has-text("${text}")`,
operationStatus: 'div.tfa-webauthn-alert',
};

const waKeyActionsSelectors = {
Expand All @@ -40,13 +40,15 @@ const ajaxRequestChecker =
export class ProfilePage {
private readonly page: Page;

private readonly operationStatusLocator: Locator;
private readonly twoFactorOptionsLocator: Locator;
private readonly webAuthnSectionLocator: Locator;
private readonly updateProfileButtonLocator: Locator;

public constructor(page: Page) {
this.page = page;

this.operationStatusLocator = page.locator(waSelectors.operationStatus);
this.twoFactorOptionsLocator = page.locator(selectors.twoFactorOptions);
this.webAuthnSectionLocator = page.locator(selectors.webAuthnSection);
this.updateProfileButtonLocator = page.locator(selectors.updateProfileButton);
Expand All @@ -56,7 +58,7 @@ export class ProfilePage {
return this.page.goto('/wp-admin/profile.php', { waitUntil: 'domcontentloaded' });
}

public async registerKey(keyName: string): Promise<unknown> {
public async registerKey(keyName: string): Promise<Locator> {
await this.webAuthnSectionLocator.scrollIntoViewIfNeeded();

await this.webAuthnSectionLocator.locator(waSelectors.keyNameInput).fill(keyName);
Expand All @@ -66,9 +68,7 @@ export class ProfilePage {
this.webAuthnSectionLocator.locator(waSelectors.registerNewKeyButton).click(),
]);

return this.page
.locator(waSelectors.operationStatus('The key has been registered'))
.waitFor({ state: 'visible' });
return this.operationStatusLocator;
}

public async enableWebAuthnProvider(): Promise<unknown> {
Expand Down Expand Up @@ -104,7 +104,7 @@ export class ProfilePage {
return noItemsRowLocator.waitFor({ state: 'visible' });
}

public async renameKey(credentialId: string, newName: string, doRename: boolean): Promise<void> {
public async renameKey(credentialId: string, newName: string, doRename: boolean): Promise<Locator> {
const keyActionsLocator = this.webAuthnSectionLocator.locator(waSelectors.keyActions(credentialId));
const renameLinkLocator = keyActionsLocator.locator(waKeyActionsSelectors.renameKey);
const newNameInputLocator = keyActionsLocator.locator(waKeyActionsSelectors.renameKeyInput);
Expand All @@ -120,11 +120,9 @@ export class ProfilePage {
this.page.waitForResponse(ajaxRequestChecker('webauthn_rename_key')),
confirmRenameLocator.click(),
]);

await this.page
.locator(waSelectors.operationStatus(newName ? 'The key has been renamed' : 'Key name cannot be empty'))
.waitFor({ state: 'visible' });
}

return this.operationStatusLocator;
}

public getKeyNameByCID(credentialId: string): Promise<string> {
Expand Down
5 changes: 3 additions & 2 deletions tests/e2e/lib/test-helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Page, CDPSession } from '@playwright/test';
import { Page, CDPSession, expect } from '@playwright/test';
import { LoginPage } from './loginpage';
import type { Protocol } from 'playwright-core/types/protocol';
import { ProfilePage } from './profilepage';
Expand All @@ -18,7 +18,8 @@ export async function registerKey(
): Promise<Protocol.WebAuthn.Credential> {
const profilePage = new ProfilePage(page);
await profilePage.visit();
await profilePage.registerKey(keyName);
const locator = await profilePage.registerKey(keyName);
await expect(locator).toContainText('The key has been registered');

const credentials = await getCredentials(client, authenticatorId);
return credentials[0];
Expand Down
6 changes: 4 additions & 2 deletions tests/e2e/specs/rename.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ test('Rename Key Workflow', async ({ page }) => {
const recodedCID1 = credential1Id.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const recodedCID2 = credential2Id.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
await profilePage.renameKey(recodedCID1, newKey1Name, false);
await profilePage.renameKey(recodedCID2, newKey2Name, true);
const locator = await profilePage.renameKey(recodedCID2, newKey2Name, true);
await expect(locator).toContainText('The key has been renamed');

const [actualKeyName1, actualKeyName2] = await Promise.all([
profilePage.getKeyNameByCID(recodedCID1),
Expand All @@ -69,7 +70,8 @@ test('Rename Key Workflow', async ({ page }) => {
expect(page.url()).toContain('/wp-admin/profile.php');
const profilePage = new ProfilePage(page);
const recodedCID1 = credential1Id.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
await profilePage.renameKey(recodedCID1, '', true);
const locator = await profilePage.renameKey(recodedCID1, '', true);
await expect(locator).toContainText('Key name cannot be empty');

const actualKeyName1 = await profilePage.getKeyNameByCID(recodedCID1);
const expectedKey1Name = key1Name;
Expand Down

0 comments on commit c6fd212

Please sign in to comment.