Skip to content

Commit

Permalink
feat: Programmatically determine when links should open in new tabs (#…
Browse files Browse the repository at this point in the history
…1100)

Closes #1071 

## Changes

- New hook `useIsNewTabImplied` that determines when links should open
in new tabs
- Codifies logic outlined in
cfpb/sbl-project#295
- Update test utilities:
  - Rename to clarify their intent (`openLink`, `openLinkNewTab`)
  - New helpers (`expectLinkOpensSameTab`, `expectLinkOpensNewTab`)
- Add E2E tests to verify link targets on each page
  - Unauthenticated homepage
  - Complete your user profile
  - Authenticated landing page
  - View your user profile
  - View your financial institution profile
  - Updated your financial institution profile
  - Filing home for each filing step
    - Start filing
    - Resolve syntax errors
    - Resolve logic errors
    - Review warnings
    - Provide filing details
    - Sign and Submit
  - Filing homepage for each step of the Filing process
    - Provide type of financial institution 
    - Upload file
    - Resolve syntax errors
    - Resolve logic errors
    - Review warnings
    - Provide filing details
    - Sign and submit
  • Loading branch information
meissadia authored Jan 22, 2025
1 parent 38c6946 commit e253495
Show file tree
Hide file tree
Showing 25 changed files with 1,061 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { test } from '../../../fixtures/testFixture';
import { expectLinkOpensSameTab } from '../../../utils/openLink';
import {
SelectorLinkText,
expectAll,
selectCrumbtrailLink,
selectLinks,
} from '../../../utils/verifyLinkTargets';

test('Complete user profile: Verify link targets', async ({ page }) => {
const unauthenticatedHome = selectCrumbtrailLink(
page,
SelectorLinkText.crumbtrail.home,
);

const linksByText = selectLinks(page, [
SelectorLinkText.gleif.long,
SelectorLinkText.privacyNotice,
]);

await expectAll(
[unauthenticatedHome, ...linksByText],
expectLinkOpensSameTab,
);
});
169 changes: 169 additions & 0 deletions e2e/pages/filing-app/filing-home/VerifyLinkTargets.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import type { Page } from '@playwright/test';
import { expect } from '@playwright/test';
import { InstitutionCardTitle } from 'pages/Filing/FilingApp/InstitutionCard.helpers';
import { test } from '../../../fixtures/testFixture';
import { expectLinkOpensNewTab } from '../../../utils/openLink';
import {
SelectorLinkText,
expectAll,
selectLinks,
} from '../../../utils/verifyLinkTargets';

/**
* Helpers
* */

// Verify a button with the given label is visible
const expectButtonVisible = async (page: Page, name: string) => {
const button = page.getByRole('button', { name });
await expect(button).toBeVisible();
};

// Labels for primary home page actions
const ActionLabel = {
startFiling: 'Start filing',
continueFiling: 'Continue filing',
};

// Verify we've navigated to the Filing homepage
const gotoFilingHome = async (page: Page) => {
await page.goto('/filing');

await expect(page.locator('h1')).toContainText(
'File your small business lending data',
);
};

/**
* Tests - Verify the state of the Filing homepage at each stage of the Filing process
* */

test('Start filing', async ({ page, navigateToFilingHome }) => {
navigateToFilingHome;

await expect(page.getByText(InstitutionCardTitle.start)).toBeVisible();

const links = selectLinks(page, [
SelectorLinkText.fig.long,
SelectorLinkText.fig.readAboutFiling,
]);

await expectAll(links, expectLinkOpensNewTab);

await expectButtonVisible(page, ActionLabel.startFiling);
});

test('Provide type of financial institution', async ({
page,
navigateToProvideTypeOfFinancialInstitution,
}) => {
navigateToProvideTypeOfFinancialInstitution;
await gotoFilingHome(page);

await expect(page.getByText(InstitutionCardTitle.start)).toBeVisible();

const links = selectLinks(page, [
SelectorLinkText.fig.long,
SelectorLinkText.fig.readAboutFiling,
]);

await expectAll(links, expectLinkOpensNewTab);
});

test('Upload file', async ({ page, navigateToUploadFile }) => {
navigateToUploadFile;
await gotoFilingHome(page);

await expect(page.getByText(InstitutionCardTitle.upload)).toBeVisible();
await expectButtonVisible(page, ActionLabel.continueFiling);

const links = selectLinks(page, [
SelectorLinkText.fig.long,
SelectorLinkText.fig.readAboutFiling,
]);

await expectAll(links, expectLinkOpensNewTab);
});

test('Logic errors', async ({
page,
navigateToLogicErrorsAfterLogicErrorsUpload,
}) => {
navigateToLogicErrorsAfterLogicErrorsUpload;
await gotoFilingHome(page);

await expect(page.getByText(InstitutionCardTitle.errors)).toBeVisible();
await expectButtonVisible(page, ActionLabel.continueFiling);

const links = selectLinks(page, [
SelectorLinkText.fig.long,
SelectorLinkText.fig.readAboutValidations,
]);

await expectAll(links, expectLinkOpensNewTab);
});

test('Syntax errors', async ({
page,
navigateToSyntaxErrorsAfterSyntaxErrorsUpload,
}) => {
navigateToSyntaxErrorsAfterSyntaxErrorsUpload;
await gotoFilingHome(page);

await expect(page.getByText(InstitutionCardTitle.errors)).toBeVisible();
await expectButtonVisible(page, ActionLabel.continueFiling);

const links = selectLinks(page, [
SelectorLinkText.fig.long,
SelectorLinkText.fig.readAboutValidations,
]);

await expectAll(links, expectLinkOpensNewTab);
});

test('Warnings', async ({
page,
navigateToReviewWarningsAfterOnlyWarningsUpload,
}) => {
navigateToReviewWarningsAfterOnlyWarningsUpload;
await gotoFilingHome(page);

await expect(page.getByText(InstitutionCardTitle.warnings)).toBeVisible();
await expectButtonVisible(page, ActionLabel.continueFiling);

const links = selectLinks(page, [
SelectorLinkText.fig.long,
SelectorLinkText.fig.readAboutValidations,
]);

await expectAll(links, expectLinkOpensNewTab);
});

test('Provide filing details', async ({
page,
navigateToProvideFilingDetails,
}) => {
navigateToProvideFilingDetails;
await gotoFilingHome(page);

await expect(
page.getByText(InstitutionCardTitle.provideDetails),
).toBeVisible();
await expectButtonVisible(page, ActionLabel.continueFiling);

const links = selectLinks(page, [SelectorLinkText.fig.long]);

await expectAll(links, expectLinkOpensNewTab);
});

test('Sign and submit', async ({ page, navigateToSignAndSubmit }) => {
navigateToSignAndSubmit;
await gotoFilingHome(page);

await expect(page.getByText(InstitutionCardTitle.signSubmit)).toBeVisible();
await expectButtonVisible(page, ActionLabel.continueFiling);

const links = selectLinks(page, [SelectorLinkText.fig.long]);

await expectAll(links, expectLinkOpensNewTab);
});
45 changes: 45 additions & 0 deletions e2e/pages/filing-app/filing-step-routing/errorsLogic.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { expect } from '@playwright/test';
import { test } from '../../../fixtures/testFixture';
import {
expectLinkOpensNewTab,
expectLinkOpensSameTab,
} from '../../../utils/openLink';
import { checkSnapshot } from '../../../utils/snapshotTesting';
import {
SelectorLinkText,
expectAll,
expectLogoutButtonVisible,
selectAllNavLinks,
selectLink,
} from '../../../utils/verifyLinkTargets';
import { verifyRedirects } from './_shared';

const testLabel = 'Filing step routing (Errors: Logic)';
Expand Down Expand Up @@ -28,3 +40,36 @@ test(
await checkSnapshot(page);
},
);

test('Verify link targets (Errors: Logic)', async ({
page,
navigateToLogicErrorsAfterLogicErrorsUpload,
}) => {
navigateToLogicErrorsAfterLogicErrorsUpload;

// Same tab
const navlinks = await selectAllNavLinks(page);
expect(navlinks.length).toEqual(3);
await expectAll(navlinks, expectLinkOpensSameTab);

await expectLogoutButtonVisible(page);

const uploadNewFile = selectLink(page, SelectorLinkText.upload.aNewFile);
await expectLinkOpensSameTab(uploadNewFile);

// New tab
const figErrorDefinitions = await page
.locator('.validation-info-section a')
.all();
for (const figPage of figErrorDefinitions) {
// eslint-disable-next-line no-await-in-loop
const errorLabel = await figPage.textContent();
// eslint-disable-next-line no-await-in-loop
await test.step(`FIG error description link opens new tab: ${errorLabel}`, async () => {
await expectLinkOpensNewTab(figPage);
});
}

const figDataValidation = selectLink(page, SelectorLinkText.fig.section4);
await expectLinkOpensNewTab(figDataValidation);
});
45 changes: 45 additions & 0 deletions e2e/pages/filing-app/filing-step-routing/errorsSyntax.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { expect } from '@playwright/test';
import { test } from '../../../fixtures/testFixture';
import {
expectLinkOpensNewTab,
expectLinkOpensSameTab,
} from '../../../utils/openLink';
import { checkSnapshot } from '../../../utils/snapshotTesting';
import {
SelectorLinkText,
expectAll,
expectLogoutButtonVisible,
selectAllNavLinks,
selectLink,
} from '../../../utils/verifyLinkTargets';
import { verifyRedirects } from './_shared';

const testLabel = 'Filing step routing (Errors: Syntax)';
Expand Down Expand Up @@ -33,3 +45,36 @@ test(
await checkSnapshot(page);
},
);

test('Verify link targets (Errors: Syntax)', async ({
page,
navigateToSyntaxErrorsAfterSyntaxErrorsUpload,
}) => {
navigateToSyntaxErrorsAfterSyntaxErrorsUpload;

// Same tab
const navlinks = await selectAllNavLinks(page);
expect(navlinks.length).toEqual(3);
await expectAll(navlinks, expectLinkOpensSameTab);

await expectLogoutButtonVisible(page);

const uploadNewFile = selectLink(page, SelectorLinkText.upload.aNewFile);
await expectLinkOpensSameTab(uploadNewFile);

// New tab
const figErrorDefinitions = await page
.locator('.validation-info-section a')
.all();
for (const figPage of figErrorDefinitions) {
// eslint-disable-next-line no-await-in-loop
const errorLabel = await figPage.textContent();
// eslint-disable-next-line no-await-in-loop
await test.step(`FIG error description link opens new tab: ${errorLabel}`, async () => {
await expectLinkOpensNewTab(figPage);
});
}

const figDataValidation = selectLink(page, SelectorLinkText.fig.section4);
await expectLinkOpensNewTab(figDataValidation);
});
41 changes: 41 additions & 0 deletions e2e/pages/filing-app/filing-step-routing/pointOfContact.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { expect } from '@playwright/test';
import { test } from '../../../fixtures/testFixture';
import {
expectLinkOpensNewTab,
expectLinkOpensSameTab,
} from '../../../utils/openLink';
import { checkSnapshot } from '../../../utils/snapshotTesting';
import {
SelectorLinkText,
expectAll,
expectLogoutButtonVisible,
selectAllNavLinks,
selectLink,
} from '../../../utils/verifyLinkTargets';
import { verifyRedirects } from './_shared';

const testLabel = 'Filing step routing (Point of Contact)';
Expand All @@ -25,3 +37,32 @@ test(testLabel, async ({ page, navigateToProvideFilingDetails }) => {
});
await checkSnapshot(page);
});

test('Verify link targets (Provide filing details)', async ({
page,
navigateToProvideFilingDetails,
}) => {
navigateToProvideFilingDetails;

// Same tab
const navlinks = await selectAllNavLinks(page);
expect(navlinks.length).toEqual(3);
await expectAll(navlinks, expectLinkOpensSameTab);

await expectLogoutButtonVisible(page);

// New tab
const indexRegLinks = await page.locator('a:has-text("§")').all();

for (const indexRegPage of indexRegLinks) {
// eslint-disable-next-line no-await-in-loop
const title = await indexRegPage.textContent();
// eslint-disable-next-line no-await-in-loop
await test.step(`iRegs link opens new tab: ${title}`, async () => {
await expectLinkOpensNewTab(indexRegPage);
});
}

const privacyNotice = selectLink(page, SelectorLinkText.privacyNotice);
await expectLinkOpensNewTab(privacyNotice);
});
Loading

0 comments on commit e253495

Please sign in to comment.