Skip to content

Commit 121069a

Browse files
committed
Add freshbooks example
1 parent 9494bb6 commit 121069a

File tree

15 files changed

+129
-28
lines changed

15 files changed

+129
-28
lines changed

.gitignore

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,7 @@ web_modules/
7373
.yarn-integrity
7474

7575
# dotenv environment variable files
76-
.env
77-
.env.development.local
78-
.env.test.local
79-
.env.production.local
80-
.env.local
76+
.env*
8177

8278
# parcel-bundler cache (https://parceljs.org/)
8379
.cache
@@ -134,3 +130,4 @@ dist
134130
/playwright-report/
135131
/blob-report/
136132
/playwright/.cache/
133+
downloads

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"license": "ISC",
1010
"devDependencies": {
1111
"@mablhq/playwright-reporter": "0.2.1",
12-
"@mablhq/playwright-tools": "2.51.37",
12+
"@mablhq/playwright-tools": "2.51.42",
1313
"@playwright/test": "1.50.0",
1414
"@types/node": "22.12.0",
1515
"dotenv": "16.4.7"

playwright.config.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ dotenv.config({ path: path.resolve(__dirname, '.env') });
77
* See https://playwright.dev/docs/test-configuration.
88
*/
99
export default defineConfig({
10-
testDir: './tests',
10+
timeout: 120_000,
11+
testDir: "./tests",
1112
/* Run tests in files in parallel */
1213
fullyParallel: true,
1314
/* Fail the build on CI if you accidentally left test.only in the source code. */
@@ -17,31 +18,49 @@ export default defineConfig({
1718
/* Opt out of parallel tests on CI. */
1819
workers: process.env.CI ? 1 : undefined,
1920
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
20-
reporter: 'html',
21+
reporter: [
22+
["html"],
23+
["list", { printSteps: true }],
24+
[
25+
"@mablhq/playwright-reporter",
26+
{
27+
apiKey: process.env.MABL_API_KEY,
28+
workspaceId: process.env.MABL_WORKSPACE_ID,
29+
planName: "Playwright Tests",
30+
},
31+
],
32+
],
2133
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
2234
use: {
2335
/* Base URL to use in actions like `await page.goto('/')`. */
2436
// baseURL: 'http://127.0.0.1:3000',
2537

26-
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
27-
trace: 'on-first-retry',
38+
trace: "on",
39+
screenshot: "on",
2840
},
2941

3042
/* Configure projects for major browsers */
3143
projects: [
3244
{
33-
name: 'chromium',
34-
use: { ...devices['Desktop Chrome'] },
45+
name: "FreshBooks chromium",
46+
use: {
47+
baseURL: "https://my.freshbooks.com",
48+
...devices["Desktop Chrome"],
49+
},
50+
},
51+
{
52+
name: "chromium",
53+
use: { ...devices["Desktop Chrome"] },
3554
},
3655

3756
{
38-
name: 'firefox',
39-
use: { ...devices['Desktop Firefox'] },
57+
name: "firefox",
58+
use: { ...devices["Desktop Firefox"] },
4059
},
4160

4261
{
43-
name: 'webkit',
44-
use: { ...devices['Desktop Safari'] },
62+
name: "webkit",
63+
use: { ...devices["Desktop Safari"] },
4564
},
4665

4766
/* Test against mobile viewports. */
File renamed without changes.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { BrowserContext, Page } from '@playwright/test';
2+
import {test, expect} from '../fixtures';
3+
import { MablFixtures, MablToolset } from '@mablhq/playwright-tools';
4+
5+
test.describe.configure({ mode: 'serial' });
6+
7+
test('Create an invoice', async ({context, page, mabl}) => {
8+
await login(context, page, mabl);
9+
await page.getByLabel('Invoices').click();
10+
await page.getByRole('link', { name: 'New Invoice', exact: true }).click();
11+
12+
await page.getByLabel('Invoices', {exact: true}).click();
13+
await page.getByRole('link', { name: 'New Invoice', exact: true }).click();
14+
const invoiceNumber = await page.getByPlaceholder('Enter an Invoice #').inputValue();
15+
16+
await page.getByPlaceholder('Select a Client').click();
17+
await page.locator('[data-option-index="0"]').click();
18+
await page.getByText('$').first().click();
19+
20+
await page.locator('.invoice-addLineItem').click();
21+
await page.getByText('Item 1').click();
22+
await expect(page.getByText('$').first()).toHaveText('$750.00');
23+
24+
25+
await page.getByLabel('Save').click();
26+
27+
// See details
28+
await page.locator(`[data-invoicenumber="${invoiceNumber}"]`).click();
29+
30+
await expect(page.getByRole('heading', { name: `Invoice ${invoiceNumber}`, exact: true })).toBeVisible();
31+
32+
// TODO: How we test PDF?
33+
await page.getByLabel('More Actions').click();
34+
35+
const downloadPromise = page.waitForEvent('download');
36+
37+
await page.locator('.js-download-pdf-invoice-more-actions').click();
38+
39+
const download = await downloadPromise;
40+
await download.saveAs(`./downloads/${invoiceNumber}.pdf`);
41+
42+
// create a Page for the downloaded PDF to open in
43+
const pageForPdf = await context.newPage();
44+
45+
// use the mabl tools to open the file in a new Page
46+
await mabl.openPdfFile(`./downloads/${invoiceNumber}.pdf`, pageForPdf);
47+
48+
const aiResult = await mabl.evaluateGenAiAssertion(
49+
pageForPdf,
50+
`
51+
This is an invoice for $750.00
52+
The invoice is in English.
53+
The invoice has no images at all.
54+
`);
55+
56+
expect(aiResult.success).toBeTruthy();
57+
});
58+
59+
async function login(context: BrowserContext, page: Page, mabl: MablToolset) {
60+
// Print friendly current time
61+
console.log(`Running test at ${new Date().toISOString()}`);
62+
const credential = await mabl.getCredentials(process.env.MABL_CREDENTIALS_ID!);
63+
const emailPage = await context.newPage();
64+
65+
const mablEmailPromise = mabl.waitForEmail(credential.username, emailPage, {
66+
lookbackTimeMs: 1,
67+
});
68+
69+
await page.goto("/");
70+
await page.getByLabel("Email").fill(credential.username);
71+
await page.getByLabel("Password").fill(credential.password);
72+
73+
await page.getByRole("button", { name: "Log In" }).click();
74+
75+
const mablEmail = await mablEmailPromise;
76+
await mablEmail.open();
77+
78+
const code = (await mablEmail
79+
.getBodyLocator()
80+
.locator(".two-factor-auth-code-container")
81+
.textContent())!;
82+
await page.getByLabel("Verification code digit 1").pressSequentially(code);
83+
await emailPage.close();
84+
}
85+

tests/mabl-demos/credentials.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {expect, test} from './utils/fixtures';
2-
import {SandboxPage} from './utils/SandboxPage';
1+
import {expect, test} from '../fixtures';
2+
import {SandboxPage} from './pom/SandboxPage';
33

44
const MFA_CREDENTIALS_ID = process.env.MABL_CREDENTIALS_ID!;
55

tests/mabl-demos/database.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {expect, test} from './utils/fixtures';
1+
import { expect, test } from "../fixtures";
22

33
const MABL_DATABASE_CONNECTION = process.env.MABL_DATABASE_ID!;
44

tests/mabl-demos/email.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {SandboxPage} from './utils/SandboxPage';
2-
import {expect, test} from './utils/fixtures';
1+
import {SandboxPage} from './pom/SandboxPage';
2+
import { expect, test } from "../fixtures";
33

44
test('Validate emails can be received using mabl sandbox app', async ({
55
page,

tests/mabl-demos/genAi.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {expect, test} from './utils/fixtures';
1+
import { expect, test } from "../fixtures";
22

33
test('Evaluate a GenAI assertion to validate the state of a page', async ({
44
page,

0 commit comments

Comments
 (0)