@empiricalrun/playwright-utils 0.14.2 → 0.14.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @empiricalrun/playwright-utils
2
2
 
3
+ ## 0.14.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [ff77220]
8
+ - @empiricalrun/r2-uploader@0.3.4
9
+
10
+ ## 0.14.3
11
+
12
+ ### Patch Changes
13
+
14
+ - 3c9f929: feat: AuthStore API changes, better login logic, docs
15
+
3
16
  ## 0.14.2
4
17
 
5
18
  ### Patch Changes
@@ -3,11 +3,16 @@ type WithKey<T> = T & {
3
3
  key: string;
4
4
  };
5
5
  export declare class AuthStore<T extends WithKey<{}>> {
6
- private page;
7
- private userContext;
8
- private loginFunc;
9
- private checkLoggedInFunc;
10
- constructor(page: Page, userContext: T, loginFunc: (page: Page, userContext: T) => Promise<void>, checkLoggedInFunc: (page: Page, userContext: T) => Promise<boolean>);
6
+ page: Page;
7
+ userContext: T;
8
+ loginFunc: (page: Page, userContext: T) => Promise<void>;
9
+ checkLoggedInFunc: (page: Page, userContext: T) => Promise<boolean>;
10
+ constructor({ page, userContext, loginFunc, checkLoggedInFunc, }: {
11
+ page: Page;
12
+ userContext: T;
13
+ loginFunc: (page: Page, userContext: T) => Promise<void>;
14
+ checkLoggedInFunc: (page: Page, userContext: T) => Promise<boolean>;
15
+ });
11
16
  loginIfRequired(): Promise<void>;
12
17
  static location(userContext: {
13
18
  key: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE/C,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,qBAAa,SAAS,CAAC,CAAC,SAAS,OAAO,CAAC,EAAE,CAAC;IAExC,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,iBAAiB;gBAHjB,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,CAAC,EACd,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EACxD,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;IAGvE,eAAe;IAwBrB,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;CAGtD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE/C,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,qBAAa,SAAS,CAAC,CAAC,SAAS,OAAO,CAAC,EAAE,CAAC;IAC1C,IAAI,EAAE,IAAI,CAAC;IACX,WAAW,EAAE,CAAC,CAAC;IACf,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;gBACxD,EACV,IAAI,EACJ,WAAW,EACX,SAAS,EACT,iBAAiB,GAClB,EAAE;QACD,IAAI,EAAE,IAAI,CAAC;QACX,WAAW,EAAE,CAAC,CAAC;QACf,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACzD,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KACrE;IAOK,eAAe;IAgCrB,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;CAGtD"}
@@ -1,13 +1,17 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.AuthStore = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
4
8
  const playwright_core_1 = require("playwright-core");
5
9
  class AuthStore {
6
10
  page;
7
11
  userContext;
8
12
  loginFunc;
9
13
  checkLoggedInFunc;
10
- constructor(page, userContext, loginFunc, checkLoggedInFunc) {
14
+ constructor({ page, userContext, loginFunc, checkLoggedInFunc, }) {
11
15
  this.page = page;
12
16
  this.userContext = userContext;
13
17
  this.loginFunc = loginFunc;
@@ -15,21 +19,31 @@ class AuthStore {
15
19
  }
16
20
  async loginIfRequired() {
17
21
  let shouldDoLogin = false;
18
- try {
19
- const hasLoggedIn = await this.checkLoggedInFunc(this.page, this.userContext);
20
- shouldDoLogin = !hasLoggedIn;
22
+ const storagePath = AuthStore.location(this.userContext);
23
+ if (!fs_1.default.existsSync(storagePath)) {
24
+ shouldDoLogin = true;
21
25
  }
22
- catch (err) {
23
- if (err instanceof playwright_core_1.errors.TimeoutError) {
24
- shouldDoLogin = true;
26
+ else {
27
+ const browser = this.page.context().browser();
28
+ const newContext = await browser.newContext({
29
+ storageState: storagePath,
30
+ });
31
+ const page = await newContext.newPage();
32
+ try {
33
+ const hasLoggedIn = await this.checkLoggedInFunc(page, this.userContext);
34
+ shouldDoLogin = !hasLoggedIn;
25
35
  }
26
- else {
27
- throw err;
36
+ catch (err) {
37
+ if (err instanceof playwright_core_1.errors.TimeoutError) {
38
+ shouldDoLogin = true;
39
+ }
40
+ else {
41
+ throw err;
42
+ }
28
43
  }
29
44
  }
30
45
  if (shouldDoLogin) {
31
46
  await this.loginFunc(this.page, this.userContext);
32
- const storagePath = AuthStore.location(this.userContext);
33
47
  await this.page.context().storageState({ path: storagePath });
34
48
  }
35
49
  }
package/docs/auth.md CHANGED
@@ -4,7 +4,7 @@ This builds around playwright's `storageState` primitive which is used to cache
4
4
  auth related state (in a json file on disk).
5
5
 
6
6
  This requires an object of `UserContext` type, which has a `key: string`. The
7
- rest of the object can be custom.
7
+ rest of the object can be custom. See [section](#set-up-usercontext) on how to do that.
8
8
 
9
9
  ## Usage
10
10
 
@@ -46,3 +46,71 @@ projects: [
46
46
  }
47
47
  ]
48
48
  ```
49
+
50
+ ## Set up UserContext
51
+
52
+ - Create the `UserContext` type and implementations of that type in `test-data/index.ts`
53
+ - Create `TestOptions` in `fixtures.ts` that has all options that can be configured
54
+ - Configure fixtures and `playwright.config.ts` to use `TestOptions` type
55
+ - Set the `userContext` in the project.use field
56
+ - For setup projects, add `userContext` only
57
+ - For test/teardown projects, add `userContext` and `storageState` both
58
+
59
+ ```ts
60
+ // fixtures.ts
61
+ import { baseTestFixture } from "@empiricalrun/playwright-utils/test";
62
+ import { UserContext, primaryUser } from "./test-data";
63
+
64
+ export type TestOptions = {
65
+ userContext: UserContext;
66
+ }
67
+
68
+ export const test = baseTestFixture(base).extend<TestOptions>({
69
+ userContext: [primaryUser, { option: true }],
70
+ });
71
+ ```
72
+
73
+ ```ts
74
+ // playwright.config.ts
75
+ import { defineConfig } from "@playwright/test";
76
+ import { AuthStore } from "@empiricalrun/playwright-utils";
77
+ import { TestOptions } from "./tests/fixtures";
78
+ import { someTypeOfUser } from "./tests/test-data";
79
+
80
+ export default defineConfig<TestOptions>({
81
+ ...baseConfig,
82
+ projects: [
83
+ {
84
+ name: "setup",
85
+ use: {
86
+ // NOTE: Don't send storageState to setup
87
+ // Playwright will fail attempting to load non-existent file
88
+ // AuthStore finds it own it's own
89
+ userContext: someTypeOfUser
90
+ },
91
+ },
92
+ {
93
+ name: "chromium",
94
+ use: {
95
+ userContext: someTypeOfUser
96
+ storageState: AuthStore.location(someTypeOfUser)
97
+ },
98
+ },
99
+ ],
100
+ });
101
+ ```
102
+
103
+ ## Structuring tests across projects
104
+
105
+ Structure tests based on which user context they depend on
106
+ - If 2 tests depend on 2 different user contexts, they will be in 2 different projects
107
+
108
+ ### Multiplayer
109
+
110
+ If a test requires 2 user context (multi-user scenarios), then
111
+ - define user contexts for both the users
112
+ - for sequential execution (admin does foo, user does bar)
113
+ - use `page` for the admin, and then login on the same page with the other user context
114
+ - for parallel execution (host and guest join room together)
115
+ - create 2 pages in the fixtures: `hostPage`, `guestPage` belonging to 2 different browser contexts
116
+ - in the fixture, use AuthStore to login if required
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empiricalrun/playwright-utils",
3
- "version": "0.14.2",
3
+ "version": "0.14.4",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"
@@ -22,24 +22,24 @@
22
22
  },
23
23
  "author": "Empirical Team <hey@empirical.run>",
24
24
  "devDependencies": {
25
- "@playwright/test": "^1.47.1",
26
- "@types/node": "^20.14.9"
25
+ "@playwright/test": "1.47.1",
26
+ "@types/node": "^20.14.9",
27
+ "@types/babel__code-frame": "^7.0.6",
28
+ "@types/md5": "^2.3.5",
29
+ "@types/mime": "3.0.0"
27
30
  },
28
31
  "dependencies": {
29
32
  "@aws-sdk/client-s3": "^3.614.0",
30
33
  "@aws-sdk/s3-request-presigner": "^3.614.0",
31
34
  "@babel/code-frame": "^7.24.7",
32
- "@types/babel__code-frame": "^7.0.6",
33
- "@types/md5": "^2.3.5",
34
- "@types/mime": "3.0.0",
35
35
  "mailosaur": "^8.6.1",
36
36
  "md5": "^2.3.0",
37
37
  "mime": "3.0.0",
38
- "playwright-core": "^1.46.1",
38
+ "playwright-core": "1.47.1",
39
39
  "playwright-extra": "^4.3.6",
40
40
  "puppeteer-extra-plugin-recaptcha": "^3.6.8",
41
41
  "@empiricalrun/llm": "^0.9.4",
42
- "@empiricalrun/r2-uploader": "^0.3.3"
42
+ "@empiricalrun/r2-uploader": "^0.3.4"
43
43
  },
44
44
  "scripts": {
45
45
  "dev": "tsc --build --watch",