@entifix/testing-e2e 0.1.0-0
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/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/fixtures/entity-backend.d.ts +54 -0
- package/dist/fixtures/entity-backend.d.ts.map +1 -0
- package/dist/fixtures/entity-backend.js +130 -0
- package/dist/fixtures/entity-backend.js.map +1 -0
- package/dist/fixtures/entity-handlers.d.ts +32 -0
- package/dist/fixtures/entity-handlers.d.ts.map +1 -0
- package/dist/fixtures/entity-handlers.js +39 -0
- package/dist/fixtures/entity-handlers.js.map +1 -0
- package/dist/fixtures/fake-infrastructure.d.ts +61 -0
- package/dist/fixtures/fake-infrastructure.d.ts.map +1 -0
- package/dist/fixtures/fake-infrastructure.js +77 -0
- package/dist/fixtures/fake-infrastructure.js.map +1 -0
- package/dist/fixtures/index.d.ts +5 -0
- package/dist/fixtures/index.d.ts.map +1 -0
- package/dist/fixtures/index.js +6 -0
- package/dist/fixtures/index.js.map +1 -0
- package/dist/fixtures/signing-key.d.ts +27 -0
- package/dist/fixtures/signing-key.d.ts.map +1 -0
- package/dist/fixtures/signing-key.js +91 -0
- package/dist/fixtures/signing-key.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/playwright/assert-expected-server.d.ts +43 -0
- package/dist/playwright/assert-expected-server.d.ts.map +1 -0
- package/dist/playwright/assert-expected-server.js +98 -0
- package/dist/playwright/assert-expected-server.js.map +1 -0
- package/dist/playwright/config.d.ts +78 -0
- package/dist/playwright/config.d.ts.map +1 -0
- package/dist/playwright/config.js +96 -0
- package/dist/playwright/config.js.map +1 -0
- package/dist/playwright/entity-table.d.ts +69 -0
- package/dist/playwright/entity-table.d.ts.map +1 -0
- package/dist/playwright/entity-table.js +129 -0
- package/dist/playwright/entity-table.js.map +1 -0
- package/dist/playwright/index.d.ts +6 -0
- package/dist/playwright/index.d.ts.map +1 -0
- package/dist/playwright/index.js +7 -0
- package/dist/playwright/index.js.map +1 -0
- package/dist/playwright/session.d.ts +85 -0
- package/dist/playwright/session.d.ts.map +1 -0
- package/dist/playwright/session.js +250 -0
- package/dist/playwright/session.js.map +1 -0
- package/dist/playwright/test.d.ts +51 -0
- package/dist/playwright/test.d.ts.map +1 -0
- package/dist/playwright/test.js +79 -0
- package/dist/playwright/test.js.map +1 -0
- package/dist/profile/profile.d.ts +43 -0
- package/dist/profile/profile.d.ts.map +1 -0
- package/dist/profile/profile.js +51 -0
- package/dist/profile/profile.js.map +1 -0
- package/dist/service/define-service-e2e.d.ts +54 -0
- package/dist/service/define-service-e2e.d.ts.map +1 -0
- package/dist/service/define-service-e2e.js +57 -0
- package/dist/service/define-service-e2e.js.map +1 -0
- package/dist/service/index.d.ts +2 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +3 -0
- package/dist/service/index.js.map +1 -0
- package/package.json +131 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fixtures/index.ts"],"sourcesContent":["export * from './entity-backend.js';\nexport * from './entity-handlers.js';\nexport * from './fake-infrastructure.js';\nexport * from './signing-key.js';\n"],"names":[],"mappings":"AAAA,cAAc,sBAAsB;AACpC,cAAc,uBAAuB;AACrC,cAAc,2BAA2B;AACzC,cAAc,mBAAmB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A throwaway RSA pair the e2e suites sign and verify test tokens with.
|
|
3
|
+
*
|
|
4
|
+
* It lives here, in one place, because two sides need *the same* pair: the
|
|
5
|
+
* `mock` composition root is configured to verify with the public half, and the
|
|
6
|
+
* spec helpers sign with the private half. Generating one per file would make
|
|
7
|
+
* every token the other side cannot verify.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately **not** the development pair config-service seeds. A suite that
|
|
10
|
+
* happened to verify a real dev token would be passing for the wrong reason,
|
|
11
|
+
* and a fixture that doubles as a live credential is one copy-paste away from
|
|
12
|
+
* becoming one.
|
|
13
|
+
*/
|
|
14
|
+
export declare const E2E_KEY_ID = "e2e-key";
|
|
15
|
+
export declare const E2E_PRIVATE_KEY_PEM = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCOQ+cUUN5cVpHo\nwv8SRQYNzGLS6jrEXxzCRggsKvwZS6aa13lJpneB4M5m1K+SXK5aedOeSOl/FyQM\ncLzK/xSMF/CIscZWt5mRFQO75bKyNysUWk2WFUT0e4IZkaAypJdN1pK75XF6OaCI\nvjrP8OuBfDQ61STTzlekLyMA+ZNzwUBR29LhB1Zuh1COocLyyXYry8Tg97njZHSp\nWnmtfKg3WVgHpHLcYiQDUnD0nmjhuJXor/1samgb87k+yxXMuJWTu++sxESQMmpV\ni1iJ4zPQn7IzS799pEn/zFJgRGyIowka3f2DOY8u7O/5JDn5XCI/Qcq4rq9ky1Qa\nH901dkXPAgMBAAECggEAA26GHOp0srLbAxLRGMgrPakUfoZsXkL1+qKd1hLqe6jW\nLVbpuvgyWrEFkLEBmzXJIK9ev3JFelEgle4ECoNPXOjf0IGniWDcaiIvMcNb0Cbz\npGmZPYYE7um4PM2otWVcyeGqvOkkbPQieBu+oFSX4NkSJ7BEjHzCox9BvcryF59d\nc9oFzS97YryD8g94qH6SqgF90qxnxD5oSqz3yRuON6o6SiBwSdsT5yCTiiBIsBSb\nyZP7KN/4LPZnFaPcHJ6UtlMOPae47Z7UBdiuP8/isSyIbnU7j1+TrpXUBqqG6JFI\nEJx3rRW4yYy/syt8BkkLnKa9idbZfCgii+C/X6FNgQKBgQDAd00/+ZIp5HwRkJ7M\ne4SSPxEW9kdCdNwCG9D6GvWZO9d/eeidnM+eoTRPx9NdvfiP5ztsZEtDDfXzMQFp\nJd7Loq5Nc3ZQBchPOIoFGIruUVWlUVawgneRKggfRzDEJLlKBjbVNsPPJFEPkMyO\nXShRKR0cnY4pNen6ug6YRQn7kQKBgQC9OkqCeqVftgi5gE0VkBRf1i1bRIIClw9z\nK08XYej54JcMdYqlTdpsRK0QQYye+wVH3V0Oe2p40leDeVbQMx4W4C1/Rl+Hk05r\nQF9yvgIBPccE/D63ufcKdagj1QLHDXIHUhoMVqtaZIodBSenAV0uOtPKS+6vlVH6\nOlM+Zo+7XwKBgQCOAbiCwn7g4A/W2fEBCQXY7iWK3q3XT+fgumtnjiq2JBwtl2JV\noJTkAydY0iSXHwreCouivyF02UEmbXsP/Pw1HdQjm1SpWIriQOI9Pk2L54Ec2DXx\nSGI2Pl/9zAYkQsBf6NPeX2j8Vlxk8r6rL/sGXyJ2sZ1ptLjt4QfRu+bQsQKBgQCy\niHHOQ3sOH4iBxIx2ALdIaKHoj21+lhnMlpsLu6P9RiodZjUGm7quFemXAdF0GfA0\niqWGyWh+UC6ja/M9gk0sVhx3DeWJ27DMPjMP5jesBiZlDLz7yWhMpQ+bpxj0xznD\nsHHFHGyVX3Bzyu5LglzxBi3Wmue7H831odvybv/DTwKBgETuVvv5b2EhMbKahtnf\ndNrT9ZivoiRD4OaZBXffTG0I2HMu20a7nthKbv2o4pxztDcpW8s6UMU87N8YAK4W\nGX3DjBMHIELxRE96tjifpW9MGQijLCI+jteq4lX0Pxf6HiUB+T1jZ1KDQQfvWJpH\ncAvNvxF+Tev5A4GaIKwmahLI\n-----END PRIVATE KEY-----\n";
|
|
16
|
+
export declare const E2E_PUBLIC_KEY_PEM = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjkPnFFDeXFaR6ML/EkUG\nDcxi0uo6xF8cwkYILCr8GUummtd5SaZ3geDOZtSvklyuWnnTnkjpfxckDHC8yv8U\njBfwiLHGVreZkRUDu+WysjcrFFpNlhVE9HuCGZGgMqSXTdaSu+VxejmgiL46z/Dr\ngXw0OtUk085XpC8jAPmTc8FAUdvS4QdWbodQjqHC8sl2K8vE4Pe542R0qVp5rXyo\nN1lYB6Ry3GIkA1Jw9J5o4biV6K/9bGpoG/O5PssVzLiVk7vvrMREkDJqVYtYieMz\n0J+yM0u/faRJ/8xSYERsiKMJGt39gzmPLuzv+SQ5+VwiP0HKuK6vZMtUGh/dNXZF\nzwIDAQAB\n-----END PUBLIC KEY-----\n";
|
|
17
|
+
/**
|
|
18
|
+
* A key nothing in the fleet trusts, for the suites that assert a forged token
|
|
19
|
+
* is refused.
|
|
20
|
+
*
|
|
21
|
+
* A separate pair rather than a mangled signature, because they fail for
|
|
22
|
+
* different reasons: a corrupt signature could plausibly be caught by a
|
|
23
|
+
* structural check, while a *validly signed token from the wrong issuer's key*
|
|
24
|
+
* is the actual attack, and only a real verification catches it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const E2E_FOREIGN_PRIVATE_KEY_PEM = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgkVvRRzabj1gS\nZylt4+H7vMIL/nlCC/WoCLegBia3b9RaOkfCdXi+N99oFkcwwjywRsXmotNyPhEi\nrqFEvvxUCZQmk9Cdo2+DYzFZq/6k2/5+e3Tr3NDlvYHVaqp6CRC+DqMIorQ6TT3D\nSV/pu/Gz1U1MgE9TeB/Zw5yUjenknyjWzxeRwJjKvn10Jg2/YJzcvcsKeiED6+LU\nFVkiJsvnxUvuJWnjGmtXocb85PbN4oD54eERLGL/cxZB4p8K6P/KTQrQV207qL+m\nRqYjTj2Wu/ct4FSdGPKm5mhMP87sqioXU14t2R/nltIgiom0FajqyrR15krLkXSy\n0PrGIqbHAgMBAAECggEAT1aTrkxIRMQm6ez0cRqFOoyRuzhxtPtQ1kb8aIMxlTka\nDb03YPQHhcH4zycW5RZMw3Ms7SGuZggaEm+EOwI9js6u2AL4tTOg8aRNKbhNGiuj\ny953ruWMiMBDS28priQVlDuKPkWa1SX+aySx0j2uF8RBLhhGWgGEh2ba0yJuHCrq\nN+l7wU26loDjlwS7dTQYc8z2WvGnKBbJVUJzJaLeUyMftVCd86sgjiYX9nnVuqxo\nT9kE7/GhLOeP1vSjYj3Tk6CrQQlEanIUrSrogMt0LXVtek5sDyFPqTKnhd+bjNtl\nsTfibYU7Yq4xlV/Bu3ntJYXh0hiL4VS1bOWc1rh6oQKBgQDLtiMbPuREXwJwgYKP\nSB72RhGiT1fvklWyq43CGMsVgE43ncJAtrGb6A0fBVspYnS7YKIaUAVTyboNrycD\nJzgFaVF/m75GeQDKOoRoPRfke/ytA3NIEeAy2Vo+1ZD60SLVdvFgusuJbwrg0Vn7\noxbigMi39Bif5ADz/+nupDgoJwKBgQDJyEFLq0CSiltScR7GzkCM9rSNs2ntSNOL\nGVM7iZ32AP+UukFa02CC/s+6p660JUtFuZ6ax8npb+TAwWc2BydcRuqMQVmDMZ0j\nl1A/PNZS9myvgy+RpwCtWPJc0k2AIrMIJM6pcj/ZByxV1tJcKj19CyM03phlg9Py\nTtmkSX8QYQKBgQCnyDoeBKzJy18c/u5jyMkHmiqH/sW0olhHMpktVnJeITFLCXqn\nBlI+0N+Nv0GYUmlGs46QEXxxyGKfRrXhGPpBKr9fVQ1gyeTmq0/G8xqsq5ovffoD\nUAXSm8aCnjAtBPelzbN9MhzV80mIZaWxZmBA6kVnjXqCpq5KSWuJjGRcXQKBgBLe\n4IRkGqDZwZqfK6KqDU1hkRcjbUecpPQARVFvGE+2XjCZjp0g4Yi+rcyl++erCTQX\nHOcawh5LsZf5Pl7GIn81vp+pSObFEA4RC5cuaFjP5PAxE5TKinyrsdbOcCMIm7eq\nQY2FOsVgL1xDv96QsLlt/jfmjVgJERw7FY2QtgphAoGAcbrPfjRrDMqthf3LJsFu\nZH3hkadfbsCLld6UvAva0Vkugv5kOx0wB6+Bbk3rEGUPUxpaq1+iFhr7gUlghAA3\nlRKwXGJZJc5PIUuHoxCYg/W4rKbYlrlYAwYQaNIucTT/bUgXw6Ra5rxEqnpgKiqJ\nMUzrkxXjBuapqxOF4QzIySg=\n-----END PRIVATE KEY-----\n";
|
|
27
|
+
//# sourceMappingURL=signing-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing-key.d.ts","sourceRoot":"","sources":["../../src/fixtures/signing-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,YAAY,CAAC;AAEpC,eAAO,MAAM,mBAAmB,ysDA4B/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,idAS9B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,ysDA4BvC,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A throwaway RSA pair the e2e suites sign and verify test tokens with.
|
|
3
|
+
*
|
|
4
|
+
* It lives here, in one place, because two sides need *the same* pair: the
|
|
5
|
+
* `mock` composition root is configured to verify with the public half, and the
|
|
6
|
+
* spec helpers sign with the private half. Generating one per file would make
|
|
7
|
+
* every token the other side cannot verify.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately **not** the development pair config-service seeds. A suite that
|
|
10
|
+
* happened to verify a real dev token would be passing for the wrong reason,
|
|
11
|
+
* and a fixture that doubles as a live credential is one copy-paste away from
|
|
12
|
+
* becoming one.
|
|
13
|
+
*/ export const E2E_KEY_ID = 'e2e-key';
|
|
14
|
+
export const E2E_PRIVATE_KEY_PEM = `-----BEGIN PRIVATE KEY-----
|
|
15
|
+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCOQ+cUUN5cVpHo
|
|
16
|
+
wv8SRQYNzGLS6jrEXxzCRggsKvwZS6aa13lJpneB4M5m1K+SXK5aedOeSOl/FyQM
|
|
17
|
+
cLzK/xSMF/CIscZWt5mRFQO75bKyNysUWk2WFUT0e4IZkaAypJdN1pK75XF6OaCI
|
|
18
|
+
vjrP8OuBfDQ61STTzlekLyMA+ZNzwUBR29LhB1Zuh1COocLyyXYry8Tg97njZHSp
|
|
19
|
+
WnmtfKg3WVgHpHLcYiQDUnD0nmjhuJXor/1samgb87k+yxXMuJWTu++sxESQMmpV
|
|
20
|
+
i1iJ4zPQn7IzS799pEn/zFJgRGyIowka3f2DOY8u7O/5JDn5XCI/Qcq4rq9ky1Qa
|
|
21
|
+
H901dkXPAgMBAAECggEAA26GHOp0srLbAxLRGMgrPakUfoZsXkL1+qKd1hLqe6jW
|
|
22
|
+
LVbpuvgyWrEFkLEBmzXJIK9ev3JFelEgle4ECoNPXOjf0IGniWDcaiIvMcNb0Cbz
|
|
23
|
+
pGmZPYYE7um4PM2otWVcyeGqvOkkbPQieBu+oFSX4NkSJ7BEjHzCox9BvcryF59d
|
|
24
|
+
c9oFzS97YryD8g94qH6SqgF90qxnxD5oSqz3yRuON6o6SiBwSdsT5yCTiiBIsBSb
|
|
25
|
+
yZP7KN/4LPZnFaPcHJ6UtlMOPae47Z7UBdiuP8/isSyIbnU7j1+TrpXUBqqG6JFI
|
|
26
|
+
EJx3rRW4yYy/syt8BkkLnKa9idbZfCgii+C/X6FNgQKBgQDAd00/+ZIp5HwRkJ7M
|
|
27
|
+
e4SSPxEW9kdCdNwCG9D6GvWZO9d/eeidnM+eoTRPx9NdvfiP5ztsZEtDDfXzMQFp
|
|
28
|
+
Jd7Loq5Nc3ZQBchPOIoFGIruUVWlUVawgneRKggfRzDEJLlKBjbVNsPPJFEPkMyO
|
|
29
|
+
XShRKR0cnY4pNen6ug6YRQn7kQKBgQC9OkqCeqVftgi5gE0VkBRf1i1bRIIClw9z
|
|
30
|
+
K08XYej54JcMdYqlTdpsRK0QQYye+wVH3V0Oe2p40leDeVbQMx4W4C1/Rl+Hk05r
|
|
31
|
+
QF9yvgIBPccE/D63ufcKdagj1QLHDXIHUhoMVqtaZIodBSenAV0uOtPKS+6vlVH6
|
|
32
|
+
OlM+Zo+7XwKBgQCOAbiCwn7g4A/W2fEBCQXY7iWK3q3XT+fgumtnjiq2JBwtl2JV
|
|
33
|
+
oJTkAydY0iSXHwreCouivyF02UEmbXsP/Pw1HdQjm1SpWIriQOI9Pk2L54Ec2DXx
|
|
34
|
+
SGI2Pl/9zAYkQsBf6NPeX2j8Vlxk8r6rL/sGXyJ2sZ1ptLjt4QfRu+bQsQKBgQCy
|
|
35
|
+
iHHOQ3sOH4iBxIx2ALdIaKHoj21+lhnMlpsLu6P9RiodZjUGm7quFemXAdF0GfA0
|
|
36
|
+
iqWGyWh+UC6ja/M9gk0sVhx3DeWJ27DMPjMP5jesBiZlDLz7yWhMpQ+bpxj0xznD
|
|
37
|
+
sHHFHGyVX3Bzyu5LglzxBi3Wmue7H831odvybv/DTwKBgETuVvv5b2EhMbKahtnf
|
|
38
|
+
dNrT9ZivoiRD4OaZBXffTG0I2HMu20a7nthKbv2o4pxztDcpW8s6UMU87N8YAK4W
|
|
39
|
+
GX3DjBMHIELxRE96tjifpW9MGQijLCI+jteq4lX0Pxf6HiUB+T1jZ1KDQQfvWJpH
|
|
40
|
+
cAvNvxF+Tev5A4GaIKwmahLI
|
|
41
|
+
-----END PRIVATE KEY-----
|
|
42
|
+
`;
|
|
43
|
+
export const E2E_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
44
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjkPnFFDeXFaR6ML/EkUG
|
|
45
|
+
Dcxi0uo6xF8cwkYILCr8GUummtd5SaZ3geDOZtSvklyuWnnTnkjpfxckDHC8yv8U
|
|
46
|
+
jBfwiLHGVreZkRUDu+WysjcrFFpNlhVE9HuCGZGgMqSXTdaSu+VxejmgiL46z/Dr
|
|
47
|
+
gXw0OtUk085XpC8jAPmTc8FAUdvS4QdWbodQjqHC8sl2K8vE4Pe542R0qVp5rXyo
|
|
48
|
+
N1lYB6Ry3GIkA1Jw9J5o4biV6K/9bGpoG/O5PssVzLiVk7vvrMREkDJqVYtYieMz
|
|
49
|
+
0J+yM0u/faRJ/8xSYERsiKMJGt39gzmPLuzv+SQ5+VwiP0HKuK6vZMtUGh/dNXZF
|
|
50
|
+
zwIDAQAB
|
|
51
|
+
-----END PUBLIC KEY-----
|
|
52
|
+
`;
|
|
53
|
+
/**
|
|
54
|
+
* A key nothing in the fleet trusts, for the suites that assert a forged token
|
|
55
|
+
* is refused.
|
|
56
|
+
*
|
|
57
|
+
* A separate pair rather than a mangled signature, because they fail for
|
|
58
|
+
* different reasons: a corrupt signature could plausibly be caught by a
|
|
59
|
+
* structural check, while a *validly signed token from the wrong issuer's key*
|
|
60
|
+
* is the actual attack, and only a real verification catches it.
|
|
61
|
+
*/ export const E2E_FOREIGN_PRIVATE_KEY_PEM = `-----BEGIN PRIVATE KEY-----
|
|
62
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgkVvRRzabj1gS
|
|
63
|
+
Zylt4+H7vMIL/nlCC/WoCLegBia3b9RaOkfCdXi+N99oFkcwwjywRsXmotNyPhEi
|
|
64
|
+
rqFEvvxUCZQmk9Cdo2+DYzFZq/6k2/5+e3Tr3NDlvYHVaqp6CRC+DqMIorQ6TT3D
|
|
65
|
+
SV/pu/Gz1U1MgE9TeB/Zw5yUjenknyjWzxeRwJjKvn10Jg2/YJzcvcsKeiED6+LU
|
|
66
|
+
FVkiJsvnxUvuJWnjGmtXocb85PbN4oD54eERLGL/cxZB4p8K6P/KTQrQV207qL+m
|
|
67
|
+
RqYjTj2Wu/ct4FSdGPKm5mhMP87sqioXU14t2R/nltIgiom0FajqyrR15krLkXSy
|
|
68
|
+
0PrGIqbHAgMBAAECggEAT1aTrkxIRMQm6ez0cRqFOoyRuzhxtPtQ1kb8aIMxlTka
|
|
69
|
+
Db03YPQHhcH4zycW5RZMw3Ms7SGuZggaEm+EOwI9js6u2AL4tTOg8aRNKbhNGiuj
|
|
70
|
+
y953ruWMiMBDS28priQVlDuKPkWa1SX+aySx0j2uF8RBLhhGWgGEh2ba0yJuHCrq
|
|
71
|
+
N+l7wU26loDjlwS7dTQYc8z2WvGnKBbJVUJzJaLeUyMftVCd86sgjiYX9nnVuqxo
|
|
72
|
+
T9kE7/GhLOeP1vSjYj3Tk6CrQQlEanIUrSrogMt0LXVtek5sDyFPqTKnhd+bjNtl
|
|
73
|
+
sTfibYU7Yq4xlV/Bu3ntJYXh0hiL4VS1bOWc1rh6oQKBgQDLtiMbPuREXwJwgYKP
|
|
74
|
+
SB72RhGiT1fvklWyq43CGMsVgE43ncJAtrGb6A0fBVspYnS7YKIaUAVTyboNrycD
|
|
75
|
+
JzgFaVF/m75GeQDKOoRoPRfke/ytA3NIEeAy2Vo+1ZD60SLVdvFgusuJbwrg0Vn7
|
|
76
|
+
oxbigMi39Bif5ADz/+nupDgoJwKBgQDJyEFLq0CSiltScR7GzkCM9rSNs2ntSNOL
|
|
77
|
+
GVM7iZ32AP+UukFa02CC/s+6p660JUtFuZ6ax8npb+TAwWc2BydcRuqMQVmDMZ0j
|
|
78
|
+
l1A/PNZS9myvgy+RpwCtWPJc0k2AIrMIJM6pcj/ZByxV1tJcKj19CyM03phlg9Py
|
|
79
|
+
TtmkSX8QYQKBgQCnyDoeBKzJy18c/u5jyMkHmiqH/sW0olhHMpktVnJeITFLCXqn
|
|
80
|
+
BlI+0N+Nv0GYUmlGs46QEXxxyGKfRrXhGPpBKr9fVQ1gyeTmq0/G8xqsq5ovffoD
|
|
81
|
+
UAXSm8aCnjAtBPelzbN9MhzV80mIZaWxZmBA6kVnjXqCpq5KSWuJjGRcXQKBgBLe
|
|
82
|
+
4IRkGqDZwZqfK6KqDU1hkRcjbUecpPQARVFvGE+2XjCZjp0g4Yi+rcyl++erCTQX
|
|
83
|
+
HOcawh5LsZf5Pl7GIn81vp+pSObFEA4RC5cuaFjP5PAxE5TKinyrsdbOcCMIm7eq
|
|
84
|
+
QY2FOsVgL1xDv96QsLlt/jfmjVgJERw7FY2QtgphAoGAcbrPfjRrDMqthf3LJsFu
|
|
85
|
+
ZH3hkadfbsCLld6UvAva0Vkugv5kOx0wB6+Bbk3rEGUPUxpaq1+iFhr7gUlghAA3
|
|
86
|
+
lRKwXGJZJc5PIUuHoxCYg/W4rKbYlrlYAwYQaNIucTT/bUgXw6Ra5rxEqnpgKiqJ
|
|
87
|
+
MUzrkxXjBuapqxOF4QzIySg=
|
|
88
|
+
-----END PRIVATE KEY-----
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
//# sourceMappingURL=signing-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/fixtures/signing-key.ts"],"sourcesContent":["/**\n * A throwaway RSA pair the e2e suites sign and verify test tokens with.\n *\n * It lives here, in one place, because two sides need *the same* pair: the\n * `mock` composition root is configured to verify with the public half, and the\n * spec helpers sign with the private half. Generating one per file would make\n * every token the other side cannot verify.\n *\n * Deliberately **not** the development pair config-service seeds. A suite that\n * happened to verify a real dev token would be passing for the wrong reason,\n * and a fixture that doubles as a live credential is one copy-paste away from\n * becoming one.\n */\nexport const E2E_KEY_ID = 'e2e-key';\n\nexport const E2E_PRIVATE_KEY_PEM = `-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCOQ+cUUN5cVpHo\nwv8SRQYNzGLS6jrEXxzCRggsKvwZS6aa13lJpneB4M5m1K+SXK5aedOeSOl/FyQM\ncLzK/xSMF/CIscZWt5mRFQO75bKyNysUWk2WFUT0e4IZkaAypJdN1pK75XF6OaCI\nvjrP8OuBfDQ61STTzlekLyMA+ZNzwUBR29LhB1Zuh1COocLyyXYry8Tg97njZHSp\nWnmtfKg3WVgHpHLcYiQDUnD0nmjhuJXor/1samgb87k+yxXMuJWTu++sxESQMmpV\ni1iJ4zPQn7IzS799pEn/zFJgRGyIowka3f2DOY8u7O/5JDn5XCI/Qcq4rq9ky1Qa\nH901dkXPAgMBAAECggEAA26GHOp0srLbAxLRGMgrPakUfoZsXkL1+qKd1hLqe6jW\nLVbpuvgyWrEFkLEBmzXJIK9ev3JFelEgle4ECoNPXOjf0IGniWDcaiIvMcNb0Cbz\npGmZPYYE7um4PM2otWVcyeGqvOkkbPQieBu+oFSX4NkSJ7BEjHzCox9BvcryF59d\nc9oFzS97YryD8g94qH6SqgF90qxnxD5oSqz3yRuON6o6SiBwSdsT5yCTiiBIsBSb\nyZP7KN/4LPZnFaPcHJ6UtlMOPae47Z7UBdiuP8/isSyIbnU7j1+TrpXUBqqG6JFI\nEJx3rRW4yYy/syt8BkkLnKa9idbZfCgii+C/X6FNgQKBgQDAd00/+ZIp5HwRkJ7M\ne4SSPxEW9kdCdNwCG9D6GvWZO9d/eeidnM+eoTRPx9NdvfiP5ztsZEtDDfXzMQFp\nJd7Loq5Nc3ZQBchPOIoFGIruUVWlUVawgneRKggfRzDEJLlKBjbVNsPPJFEPkMyO\nXShRKR0cnY4pNen6ug6YRQn7kQKBgQC9OkqCeqVftgi5gE0VkBRf1i1bRIIClw9z\nK08XYej54JcMdYqlTdpsRK0QQYye+wVH3V0Oe2p40leDeVbQMx4W4C1/Rl+Hk05r\nQF9yvgIBPccE/D63ufcKdagj1QLHDXIHUhoMVqtaZIodBSenAV0uOtPKS+6vlVH6\nOlM+Zo+7XwKBgQCOAbiCwn7g4A/W2fEBCQXY7iWK3q3XT+fgumtnjiq2JBwtl2JV\noJTkAydY0iSXHwreCouivyF02UEmbXsP/Pw1HdQjm1SpWIriQOI9Pk2L54Ec2DXx\nSGI2Pl/9zAYkQsBf6NPeX2j8Vlxk8r6rL/sGXyJ2sZ1ptLjt4QfRu+bQsQKBgQCy\niHHOQ3sOH4iBxIx2ALdIaKHoj21+lhnMlpsLu6P9RiodZjUGm7quFemXAdF0GfA0\niqWGyWh+UC6ja/M9gk0sVhx3DeWJ27DMPjMP5jesBiZlDLz7yWhMpQ+bpxj0xznD\nsHHFHGyVX3Bzyu5LglzxBi3Wmue7H831odvybv/DTwKBgETuVvv5b2EhMbKahtnf\ndNrT9ZivoiRD4OaZBXffTG0I2HMu20a7nthKbv2o4pxztDcpW8s6UMU87N8YAK4W\nGX3DjBMHIELxRE96tjifpW9MGQijLCI+jteq4lX0Pxf6HiUB+T1jZ1KDQQfvWJpH\ncAvNvxF+Tev5A4GaIKwmahLI\n-----END PRIVATE KEY-----\n`;\n\nexport const E2E_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjkPnFFDeXFaR6ML/EkUG\nDcxi0uo6xF8cwkYILCr8GUummtd5SaZ3geDOZtSvklyuWnnTnkjpfxckDHC8yv8U\njBfwiLHGVreZkRUDu+WysjcrFFpNlhVE9HuCGZGgMqSXTdaSu+VxejmgiL46z/Dr\ngXw0OtUk085XpC8jAPmTc8FAUdvS4QdWbodQjqHC8sl2K8vE4Pe542R0qVp5rXyo\nN1lYB6Ry3GIkA1Jw9J5o4biV6K/9bGpoG/O5PssVzLiVk7vvrMREkDJqVYtYieMz\n0J+yM0u/faRJ/8xSYERsiKMJGt39gzmPLuzv+SQ5+VwiP0HKuK6vZMtUGh/dNXZF\nzwIDAQAB\n-----END PUBLIC KEY-----\n`;\n\n/**\n * A key nothing in the fleet trusts, for the suites that assert a forged token\n * is refused.\n *\n * A separate pair rather than a mangled signature, because they fail for\n * different reasons: a corrupt signature could plausibly be caught by a\n * structural check, while a *validly signed token from the wrong issuer's key*\n * is the actual attack, and only a real verification catches it.\n */\nexport const E2E_FOREIGN_PRIVATE_KEY_PEM = `-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgkVvRRzabj1gS\nZylt4+H7vMIL/nlCC/WoCLegBia3b9RaOkfCdXi+N99oFkcwwjywRsXmotNyPhEi\nrqFEvvxUCZQmk9Cdo2+DYzFZq/6k2/5+e3Tr3NDlvYHVaqp6CRC+DqMIorQ6TT3D\nSV/pu/Gz1U1MgE9TeB/Zw5yUjenknyjWzxeRwJjKvn10Jg2/YJzcvcsKeiED6+LU\nFVkiJsvnxUvuJWnjGmtXocb85PbN4oD54eERLGL/cxZB4p8K6P/KTQrQV207qL+m\nRqYjTj2Wu/ct4FSdGPKm5mhMP87sqioXU14t2R/nltIgiom0FajqyrR15krLkXSy\n0PrGIqbHAgMBAAECggEAT1aTrkxIRMQm6ez0cRqFOoyRuzhxtPtQ1kb8aIMxlTka\nDb03YPQHhcH4zycW5RZMw3Ms7SGuZggaEm+EOwI9js6u2AL4tTOg8aRNKbhNGiuj\ny953ruWMiMBDS28priQVlDuKPkWa1SX+aySx0j2uF8RBLhhGWgGEh2ba0yJuHCrq\nN+l7wU26loDjlwS7dTQYc8z2WvGnKBbJVUJzJaLeUyMftVCd86sgjiYX9nnVuqxo\nT9kE7/GhLOeP1vSjYj3Tk6CrQQlEanIUrSrogMt0LXVtek5sDyFPqTKnhd+bjNtl\nsTfibYU7Yq4xlV/Bu3ntJYXh0hiL4VS1bOWc1rh6oQKBgQDLtiMbPuREXwJwgYKP\nSB72RhGiT1fvklWyq43CGMsVgE43ncJAtrGb6A0fBVspYnS7YKIaUAVTyboNrycD\nJzgFaVF/m75GeQDKOoRoPRfke/ytA3NIEeAy2Vo+1ZD60SLVdvFgusuJbwrg0Vn7\noxbigMi39Bif5ADz/+nupDgoJwKBgQDJyEFLq0CSiltScR7GzkCM9rSNs2ntSNOL\nGVM7iZ32AP+UukFa02CC/s+6p660JUtFuZ6ax8npb+TAwWc2BydcRuqMQVmDMZ0j\nl1A/PNZS9myvgy+RpwCtWPJc0k2AIrMIJM6pcj/ZByxV1tJcKj19CyM03phlg9Py\nTtmkSX8QYQKBgQCnyDoeBKzJy18c/u5jyMkHmiqH/sW0olhHMpktVnJeITFLCXqn\nBlI+0N+Nv0GYUmlGs46QEXxxyGKfRrXhGPpBKr9fVQ1gyeTmq0/G8xqsq5ovffoD\nUAXSm8aCnjAtBPelzbN9MhzV80mIZaWxZmBA6kVnjXqCpq5KSWuJjGRcXQKBgBLe\n4IRkGqDZwZqfK6KqDU1hkRcjbUecpPQARVFvGE+2XjCZjp0g4Yi+rcyl++erCTQX\nHOcawh5LsZf5Pl7GIn81vp+pSObFEA4RC5cuaFjP5PAxE5TKinyrsdbOcCMIm7eq\nQY2FOsVgL1xDv96QsLlt/jfmjVgJERw7FY2QtgphAoGAcbrPfjRrDMqthf3LJsFu\nZH3hkadfbsCLld6UvAva0Vkugv5kOx0wB6+Bbk3rEGUPUxpaq1+iFhr7gUlghAA3\nlRKwXGJZJc5PIUuHoxCYg/W4rKbYlrlYAwYQaNIucTT/bUgXw6Ra5rxEqnpgKiqJ\nMUzrkxXjBuapqxOF4QzIySg=\n-----END PRIVATE KEY-----\n`;\n"],"names":["E2E_KEY_ID","E2E_PRIVATE_KEY_PEM","E2E_PUBLIC_KEY_PEM","E2E_FOREIGN_PRIVATE_KEY_PEM"],"mappings":"AAAA;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMA,aAAa,UAAU;AAEpC,OAAO,MAAMC,sBAAsB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BpC,CAAC,CAAC;AAEF,OAAO,MAAMC,qBAAqB,CAAC;;;;;;;;;AASnC,CAAC,CAAC;AAEF;;;;;;;;CAQC,GACD,OAAO,MAAMC,8BAA8B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B5C,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './profile/profile.js';\n"],"names":[],"mappings":"AAAA,cAAc,uBAAuB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type E2eEnv } from '../profile/profile.js';
|
|
2
|
+
/** Opts out of the guard, for a developer who knows what they are attaching to. */
|
|
3
|
+
export declare const ALLOW_DEV_SERVER_VAR = "R10C_E2E_ALLOW_DEV_SERVER";
|
|
4
|
+
export interface AssertExpectedServerOptions {
|
|
5
|
+
/** Where the suite is pointed, e.g. `http://localhost:3001`. */
|
|
6
|
+
readonly baseURL: string;
|
|
7
|
+
readonly env?: E2eEnv;
|
|
8
|
+
readonly fetchImpl?: typeof fetch;
|
|
9
|
+
readonly warn?: (message: string) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Refuses to run the hermetic suite against a development server.
|
|
13
|
+
*
|
|
14
|
+
* `reuseExistingServer` is what makes a local run fast, and turning it off costs
|
|
15
|
+
* a production build every time. So the reuse stays and the *assumption* is
|
|
16
|
+
* checked instead: the `mock` profile's whole claim is that it is hermetic, and
|
|
17
|
+
* attached to a dev server it is not. Turning a silent wrong answer into a loud
|
|
18
|
+
* failure is the trade — see issue #69.
|
|
19
|
+
*
|
|
20
|
+
* `live` is exempt on purpose: it expects an already-running app and makes no
|
|
21
|
+
* hermeticity claim, so which build answers is the operator's business.
|
|
22
|
+
*
|
|
23
|
+
* Only when **both** signals are unreadable does the run continue, with a
|
|
24
|
+
* warning: an app that exposes neither is not a reason to refuse to test it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const assertExpectedServer: ({ baseURL, env, fetchImpl, warn, }: AssertExpectedServerOptions) => Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* The form `defineEntifixE2eTest` calls, from an auto fixture.
|
|
29
|
+
*
|
|
30
|
+
* A fixture rather than `globalSetup`, which is where this naturally belongs:
|
|
31
|
+
* Playwright loads a `globalSetup` file through a different module path than
|
|
32
|
+
* the config and the specs, and this package is `"type": "module"` while an
|
|
33
|
+
* app's `playwright.config.ts` is CJS — the same file transpiles for one and
|
|
34
|
+
* throws `exports is not defined in ES module scope` for the other. The
|
|
35
|
+
* fixture rides the path that already works, at the cost of reporting the
|
|
36
|
+
* refusal once per test rather than once per run.
|
|
37
|
+
*
|
|
38
|
+
* The promise is cached, so the probe happens once and every subsequent test
|
|
39
|
+
* rejects with the same error instead of re-asking a server that will not have
|
|
40
|
+
* changed mid-run.
|
|
41
|
+
*/
|
|
42
|
+
export declare const assertExpectedServerOnce: (baseURL: string | undefined) => Promise<void>;
|
|
43
|
+
//# sourceMappingURL=assert-expected-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert-expected-server.d.ts","sourceRoot":"","sources":["../../src/playwright/assert-expected-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAiB,MAAM,uBAAuB,CAAC;AAEnE,mFAAmF;AACnF,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AA0BhE,MAAM,WAAW,2BAA2B;IAC1C,gEAAgE;IAChE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAiBD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAAU,oCAKxC,2BAA2B,KAAG,OAAO,CAAC,IAAI,CAiC5C,CAAC;AAKF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GACnC,SAAS,MAAM,GAAG,SAAS,KAC1B,OAAO,CAAC,IAAI,CAKd,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { isMockProfile } from '../profile/profile.js';
|
|
2
|
+
/** Opts out of the guard, for a developer who knows what they are attaching to. */ export const ALLOW_DEV_SERVER_VAR = 'R10C_E2E_ALLOW_DEV_SERVER';
|
|
3
|
+
/**
|
|
4
|
+
* Liveness, not the config's `readyPath`: every app answers it, it answers from
|
|
5
|
+
* the process alone, and it carries the one field this check needs. `readyPath`
|
|
6
|
+
* differs per app and defaults to `/`, which returns HTML.
|
|
7
|
+
*/ const LIVENESS_PATH = '/api/health/live';
|
|
8
|
+
/**
|
|
9
|
+
* The second signal, which needs no cooperation from the app at all.
|
|
10
|
+
*
|
|
11
|
+
* `next dev` serves its static assets under the literal segment `development`;
|
|
12
|
+
* a production build uses a hashed build id, so this 404s under `next start`.
|
|
13
|
+
* It is a Next internal and therefore the *fallback*, but it is the one that
|
|
14
|
+
* survives the case that motivates it: an `nx e2e` run builds into the same
|
|
15
|
+
* `.next` the running dev server owns, which corrupts that server's Turbopack
|
|
16
|
+
* cache and makes every app route — liveness included — answer `500`. A guard
|
|
17
|
+
* that only asked the app would degrade to "cannot tell" at exactly the moment
|
|
18
|
+
* it is needed.
|
|
19
|
+
*/ const DEV_ASSET_PATH = '/_next/static/development/_buildManifest.js';
|
|
20
|
+
/** A probe that hangs must not hold the whole run hostage. */ const PROBE_TIMEOUT_MS = 5000;
|
|
21
|
+
const describeMismatch = (baseURL)=>[
|
|
22
|
+
`The hermetic e2e profile attached to a DEVELOPMENT server at ${baseURL}.`,
|
|
23
|
+
'',
|
|
24
|
+
'Playwright reuses whatever already listens on the app port, so this run would',
|
|
25
|
+
'test `next dev` — a different bundle, no prerender, and with the dev fleet',
|
|
26
|
+
"behind it the real services instead of this profile's fakes. It can fail, or",
|
|
27
|
+
'pass, for reasons that have nothing to do with the code under test. The build',
|
|
28
|
+
'this run just made also writes the same `.next` the dev server owns, which',
|
|
29
|
+
'corrupts its Turbopack cache on the way past.',
|
|
30
|
+
'',
|
|
31
|
+
'Stop the dev server on that port and run again, or set',
|
|
32
|
+
`${ALLOW_DEV_SERVER_VAR}=1 to accept the risk.`
|
|
33
|
+
].join('\n');
|
|
34
|
+
/**
|
|
35
|
+
* Refuses to run the hermetic suite against a development server.
|
|
36
|
+
*
|
|
37
|
+
* `reuseExistingServer` is what makes a local run fast, and turning it off costs
|
|
38
|
+
* a production build every time. So the reuse stays and the *assumption* is
|
|
39
|
+
* checked instead: the `mock` profile's whole claim is that it is hermetic, and
|
|
40
|
+
* attached to a dev server it is not. Turning a silent wrong answer into a loud
|
|
41
|
+
* failure is the trade — see issue #69.
|
|
42
|
+
*
|
|
43
|
+
* `live` is exempt on purpose: it expects an already-running app and makes no
|
|
44
|
+
* hermeticity claim, so which build answers is the operator's business.
|
|
45
|
+
*
|
|
46
|
+
* Only when **both** signals are unreadable does the run continue, with a
|
|
47
|
+
* warning: an app that exposes neither is not a reason to refuse to test it.
|
|
48
|
+
*/ export const assertExpectedServer = async ({ baseURL, env = process.env, fetchImpl = fetch, warn = (message)=>console.warn(message) })=>{
|
|
49
|
+
if (!isMockProfile(env)) return;
|
|
50
|
+
const override = env[ALLOW_DEV_SERVER_VAR];
|
|
51
|
+
if (override !== undefined && override !== '') return;
|
|
52
|
+
const get = async (path)=>{
|
|
53
|
+
try {
|
|
54
|
+
return await fetchImpl(`${baseURL}${path}`, {
|
|
55
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS)
|
|
56
|
+
});
|
|
57
|
+
} catch (unused) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const liveness = await get(LIVENESS_PATH);
|
|
62
|
+
if ((liveness == null ? void 0 : liveness.ok) === true) {
|
|
63
|
+
const mode = (await liveness.json()).mode;
|
|
64
|
+
if (mode === 'production') return;
|
|
65
|
+
if (mode === 'development') throw new Error(describeMismatch(baseURL));
|
|
66
|
+
}
|
|
67
|
+
// The app could not answer for itself. Ask Next directly.
|
|
68
|
+
const devAsset = await get(DEV_ASSET_PATH);
|
|
69
|
+
if (devAsset === undefined) {
|
|
70
|
+
warn(`e2e: could not reach ${baseURL}; cannot tell which build is serving.`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (devAsset.ok) throw new Error(describeMismatch(baseURL));
|
|
74
|
+
};
|
|
75
|
+
/** One probe per worker process, whatever the outcome. */ let verdict;
|
|
76
|
+
/**
|
|
77
|
+
* The form `defineEntifixE2eTest` calls, from an auto fixture.
|
|
78
|
+
*
|
|
79
|
+
* A fixture rather than `globalSetup`, which is where this naturally belongs:
|
|
80
|
+
* Playwright loads a `globalSetup` file through a different module path than
|
|
81
|
+
* the config and the specs, and this package is `"type": "module"` while an
|
|
82
|
+
* app's `playwright.config.ts` is CJS — the same file transpiles for one and
|
|
83
|
+
* throws `exports is not defined in ES module scope` for the other. The
|
|
84
|
+
* fixture rides the path that already works, at the cost of reporting the
|
|
85
|
+
* refusal once per test rather than once per run.
|
|
86
|
+
*
|
|
87
|
+
* The promise is cached, so the probe happens once and every subsequent test
|
|
88
|
+
* rejects with the same error instead of re-asking a server that will not have
|
|
89
|
+
* changed mid-run.
|
|
90
|
+
*/ export const assertExpectedServerOnce = (baseURL)=>{
|
|
91
|
+
if (baseURL === undefined || baseURL === '') return Promise.resolve();
|
|
92
|
+
verdict != null ? verdict : verdict = assertExpectedServer({
|
|
93
|
+
baseURL
|
|
94
|
+
});
|
|
95
|
+
return verdict;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=assert-expected-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/playwright/assert-expected-server.ts"],"sourcesContent":["import { type E2eEnv, isMockProfile } from '../profile/profile.js';\n\n/** Opts out of the guard, for a developer who knows what they are attaching to. */\nexport const ALLOW_DEV_SERVER_VAR = 'R10C_E2E_ALLOW_DEV_SERVER';\n\n/**\n * Liveness, not the config's `readyPath`: every app answers it, it answers from\n * the process alone, and it carries the one field this check needs. `readyPath`\n * differs per app and defaults to `/`, which returns HTML.\n */\nconst LIVENESS_PATH = '/api/health/live';\n\n/**\n * The second signal, which needs no cooperation from the app at all.\n *\n * `next dev` serves its static assets under the literal segment `development`;\n * a production build uses a hashed build id, so this 404s under `next start`.\n * It is a Next internal and therefore the *fallback*, but it is the one that\n * survives the case that motivates it: an `nx e2e` run builds into the same\n * `.next` the running dev server owns, which corrupts that server's Turbopack\n * cache and makes every app route — liveness included — answer `500`. A guard\n * that only asked the app would degrade to \"cannot tell\" at exactly the moment\n * it is needed.\n */\nconst DEV_ASSET_PATH = '/_next/static/development/_buildManifest.js';\n\n/** A probe that hangs must not hold the whole run hostage. */\nconst PROBE_TIMEOUT_MS = 5_000;\n\nexport interface AssertExpectedServerOptions {\n /** Where the suite is pointed, e.g. `http://localhost:3001`. */\n readonly baseURL: string;\n readonly env?: E2eEnv;\n readonly fetchImpl?: typeof fetch;\n readonly warn?: (message: string) => void;\n}\n\nconst describeMismatch = (baseURL: string): string =>\n [\n `The hermetic e2e profile attached to a DEVELOPMENT server at ${baseURL}.`,\n '',\n 'Playwright reuses whatever already listens on the app port, so this run would',\n 'test `next dev` — a different bundle, no prerender, and with the dev fleet',\n \"behind it the real services instead of this profile's fakes. It can fail, or\",\n 'pass, for reasons that have nothing to do with the code under test. The build',\n 'this run just made also writes the same `.next` the dev server owns, which',\n 'corrupts its Turbopack cache on the way past.',\n '',\n 'Stop the dev server on that port and run again, or set',\n `${ALLOW_DEV_SERVER_VAR}=1 to accept the risk.`,\n ].join('\\n');\n\n/**\n * Refuses to run the hermetic suite against a development server.\n *\n * `reuseExistingServer` is what makes a local run fast, and turning it off costs\n * a production build every time. So the reuse stays and the *assumption* is\n * checked instead: the `mock` profile's whole claim is that it is hermetic, and\n * attached to a dev server it is not. Turning a silent wrong answer into a loud\n * failure is the trade — see issue #69.\n *\n * `live` is exempt on purpose: it expects an already-running app and makes no\n * hermeticity claim, so which build answers is the operator's business.\n *\n * Only when **both** signals are unreadable does the run continue, with a\n * warning: an app that exposes neither is not a reason to refuse to test it.\n */\nexport const assertExpectedServer = async ({\n baseURL,\n env = process.env,\n fetchImpl = fetch,\n warn = message => console.warn(message),\n}: AssertExpectedServerOptions): Promise<void> => {\n if (!isMockProfile(env)) return;\n\n const override = env[ALLOW_DEV_SERVER_VAR];\n if (override !== undefined && override !== '') return;\n\n const get = async (path: string): Promise<Response | undefined> => {\n try {\n return await fetchImpl(`${baseURL}${path}`, {\n signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),\n });\n } catch {\n return undefined;\n }\n };\n\n const liveness = await get(LIVENESS_PATH);\n if (liveness?.ok === true) {\n const mode = ((await liveness.json()) as { mode?: unknown }).mode;\n if (mode === 'production') return;\n if (mode === 'development') throw new Error(describeMismatch(baseURL));\n }\n\n // The app could not answer for itself. Ask Next directly.\n const devAsset = await get(DEV_ASSET_PATH);\n if (devAsset === undefined) {\n warn(\n `e2e: could not reach ${baseURL}; cannot tell which build is serving.`,\n );\n return;\n }\n\n if (devAsset.ok) throw new Error(describeMismatch(baseURL));\n};\n\n/** One probe per worker process, whatever the outcome. */\nlet verdict: Promise<void> | undefined;\n\n/**\n * The form `defineEntifixE2eTest` calls, from an auto fixture.\n *\n * A fixture rather than `globalSetup`, which is where this naturally belongs:\n * Playwright loads a `globalSetup` file through a different module path than\n * the config and the specs, and this package is `\"type\": \"module\"` while an\n * app's `playwright.config.ts` is CJS — the same file transpiles for one and\n * throws `exports is not defined in ES module scope` for the other. The\n * fixture rides the path that already works, at the cost of reporting the\n * refusal once per test rather than once per run.\n *\n * The promise is cached, so the probe happens once and every subsequent test\n * rejects with the same error instead of re-asking a server that will not have\n * changed mid-run.\n */\nexport const assertExpectedServerOnce = (\n baseURL: string | undefined,\n): Promise<void> => {\n if (baseURL === undefined || baseURL === '') return Promise.resolve();\n\n verdict ??= assertExpectedServer({ baseURL });\n return verdict;\n};\n"],"names":["isMockProfile","ALLOW_DEV_SERVER_VAR","LIVENESS_PATH","DEV_ASSET_PATH","PROBE_TIMEOUT_MS","describeMismatch","baseURL","join","assertExpectedServer","env","process","fetchImpl","fetch","warn","message","console","override","undefined","get","path","signal","AbortSignal","timeout","liveness","ok","mode","json","Error","devAsset","verdict","assertExpectedServerOnce","Promise","resolve"],"mappings":"AAAA,SAAsBA,aAAa,QAAQ,wBAAwB;AAEnE,iFAAiF,GACjF,OAAO,MAAMC,uBAAuB,4BAA4B;AAEhE;;;;CAIC,GACD,MAAMC,gBAAgB;AAEtB;;;;;;;;;;;CAWC,GACD,MAAMC,iBAAiB;AAEvB,4DAA4D,GAC5D,MAAMC,mBAAmB;AAUzB,MAAMC,mBAAmB,CAACC,UACxB;QACE,CAAC,6DAA6D,EAAEA,QAAQ,CAAC,CAAC;QAC1E;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,GAAGL,qBAAqB,sBAAsB,CAAC;KAChD,CAACM,IAAI,CAAC;AAET;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,uBAAuB,OAAO,EACzCF,OAAO,EACPG,MAAMC,QAAQD,GAAG,EACjBE,YAAYC,KAAK,EACjBC,OAAOC,CAAAA,UAAWC,QAAQF,IAAI,CAACC,QAAQ,EACX;IAC5B,IAAI,CAACd,cAAcS,MAAM;IAEzB,MAAMO,WAAWP,GAAG,CAACR,qBAAqB;IAC1C,IAAIe,aAAaC,aAAaD,aAAa,IAAI;IAE/C,MAAME,MAAM,OAAOC;QACjB,IAAI;YACF,OAAO,MAAMR,UAAU,GAAGL,UAAUa,MAAM,EAAE;gBAC1CC,QAAQC,YAAYC,OAAO,CAAClB;YAC9B;QACF,EAAE,eAAM;YACN,OAAOa;QACT;IACF;IAEA,MAAMM,WAAW,MAAML,IAAIhB;IAC3B,IAAIqB,CAAAA,4BAAAA,SAAUC,EAAE,MAAK,MAAM;QACzB,MAAMC,OAAO,AAAE,CAAA,MAAMF,SAASG,IAAI,EAAC,EAA0BD,IAAI;QACjE,IAAIA,SAAS,cAAc;QAC3B,IAAIA,SAAS,eAAe,MAAM,IAAIE,MAAMtB,iBAAiBC;IAC/D;IAEA,0DAA0D;IAC1D,MAAMsB,WAAW,MAAMV,IAAIf;IAC3B,IAAIyB,aAAaX,WAAW;QAC1BJ,KACE,CAAC,qBAAqB,EAAEP,QAAQ,qCAAqC,CAAC;QAExE;IACF;IAEA,IAAIsB,SAASJ,EAAE,EAAE,MAAM,IAAIG,MAAMtB,iBAAiBC;AACpD,EAAE;AAEF,wDAAwD,GACxD,IAAIuB;AAEJ;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,2BAA2B,CACtCxB;IAEA,IAAIA,YAAYW,aAAaX,YAAY,IAAI,OAAOyB,QAAQC,OAAO;IAEnEH,kBAAAA,UAAAA,UAAYrB,qBAAqB;QAAEF;IAAQ;IAC3C,OAAOuB;AACT,EAAE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type PlaywrightTestConfig } from '@playwright/test';
|
|
2
|
+
import { requireLiveUrl, resolveE2eProfile } from '../profile/profile.js';
|
|
3
|
+
export interface EntifixE2eConfigOptions {
|
|
4
|
+
/** The playwright config file — pass `__filename`, as the Nx preset wants. */
|
|
5
|
+
configFile: string;
|
|
6
|
+
/**
|
|
7
|
+
* The app's directory, relative to the workspace root, e.g.
|
|
8
|
+
* `apps/back-office-app`. The server is started from there.
|
|
9
|
+
*/
|
|
10
|
+
appDir: string;
|
|
11
|
+
/** The port that app serves on (the `300N` convention). */
|
|
12
|
+
port: number;
|
|
13
|
+
/** Spec directory, relative to the config file. */
|
|
14
|
+
testDir?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Path Playwright polls to decide the server is up, relative to the base URL.
|
|
17
|
+
*
|
|
18
|
+
* A gated app needs one, and it must be **exempt from the auth middleware and
|
|
19
|
+
* free of backend dependencies**: a cold probe against `/` gets a redirect to
|
|
20
|
+
* a sign-in origin that is not running, and one against `/api/config` gets a
|
|
21
|
+
* 500 until config-service is up. Either way the run dies on `Timed out
|
|
22
|
+
* waiting for config.webServer` before a single spec starts. Defaults to the
|
|
23
|
+
* base URL, which is right for an app with no gate.
|
|
24
|
+
*/
|
|
25
|
+
readyPath?: string;
|
|
26
|
+
/**
|
|
27
|
+
* What Playwright runs to serve the app, when `next start` alone is not
|
|
28
|
+
* enough.
|
|
29
|
+
*
|
|
30
|
+
* The one caller so far is the storefront, whose reads happen in **server
|
|
31
|
+
* components**: `page.route()` cannot see a fetch the Next process makes, so
|
|
32
|
+
* its `mock` profile launches the server under a `--import` preload that
|
|
33
|
+
* installs msw inside that process instead. Expressed here rather than
|
|
34
|
+
* through `overrides` so the cwd, the readiness URL and the reuse rule stay
|
|
35
|
+
* in one place — an override would have to restate all three to change one.
|
|
36
|
+
*
|
|
37
|
+
* Ignored outside `mock`: a `live` run talks to real services and must not
|
|
38
|
+
* start a faked one.
|
|
39
|
+
*/
|
|
40
|
+
mockServerCommand?: string;
|
|
41
|
+
/** Anything else to merge in, for a project with a genuine special case. */
|
|
42
|
+
overrides?: PlaywrightTestConfig;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The shared Playwright configuration for an entifix app e2e project.
|
|
46
|
+
*
|
|
47
|
+
* The profile decides three things, and specs decide none of them:
|
|
48
|
+
*
|
|
49
|
+
* - **which specs run** — by filename (`*.mock.spec.ts` / `*.live.spec.ts`).
|
|
50
|
+
* Selection by `testIgnore` rather than by an in-spec `test.skip` means a
|
|
51
|
+
* run with the wrong environment fails instead of quietly reporting green.
|
|
52
|
+
* - **the base URL** — the local app in `mock`; in `live` the app is expected
|
|
53
|
+
* to already be running (started with its real backend), so Playwright
|
|
54
|
+
* reuses it rather than racing a second one.
|
|
55
|
+
* - **whether a reused server is acceptable** — `mock` refuses a development
|
|
56
|
+
* one, `live` accepts whatever is there. Enforced by an auto fixture in
|
|
57
|
+
* `defineEntifixE2eTest`, not from here: Playwright loads `globalSetup`
|
|
58
|
+
* through a different module path than the one it uses for the config and the
|
|
59
|
+
* specs, and this package is `"type": "module"` while an app's
|
|
60
|
+
* `playwright.config.ts` is CJS — a file reached both ways transpiles for one
|
|
61
|
+
* and fails for the other. See `assertExpectedServer`.
|
|
62
|
+
*
|
|
63
|
+
* Browsers are chromium in both profiles unless `E2E_BROWSERS=all`.
|
|
64
|
+
*/
|
|
65
|
+
export declare const defineEntifixE2eConfig: ({ configFile, appDir, port, testDir, readyPath, mockServerCommand, overrides, }: EntifixE2eConfigOptions) => PlaywrightTestConfig;
|
|
66
|
+
/**
|
|
67
|
+
* Re-exported so a Playwright suite reaches both from this entry point.
|
|
68
|
+
*
|
|
69
|
+
* ⚠️ Not only for convenience. `@nx/enforce-module-boundaries` treats a package
|
|
70
|
+
* that any file in the consuming project loads with a dynamic `import()` as
|
|
71
|
+
* lazy-loaded, and then refuses every *static* import of it — and
|
|
72
|
+
* `marketplace-app-e2e` has one: its msw preload must call `register()` for the
|
|
73
|
+
* resolver hook before it resolves anything, so its imports cannot be hoisted.
|
|
74
|
+
* The rule keys on the specifier, so a `live` spec there can reach
|
|
75
|
+
* `requireLiveUrl` through `/playwright` and not through the root entry.
|
|
76
|
+
*/
|
|
77
|
+
export { requireLiveUrl, resolveE2eProfile };
|
|
78
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/playwright/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAEL,cAAc,EACd,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;;OAaG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4EAA4E;IAC5E,SAAS,CAAC,EAAE,oBAAoB,CAAC;CAClC;AAuBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,sBAAsB,GAAI,iFAQpC,uBAAuB,KAAG,oBAuC5B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { workspaceRoot } from '@nx/devkit';
|
|
4
|
+
import { nxE2EPreset } from '@nx/playwright/preset';
|
|
5
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
6
|
+
import { isMockProfile, requireLiveUrl, resolveE2eProfile } from '../profile/profile.js';
|
|
7
|
+
/**
|
|
8
|
+
* Every browser Playwright can drive.
|
|
9
|
+
*
|
|
10
|
+
* Chromium is the default in **both** profiles. Interception happens through
|
|
11
|
+
* `page.route()`, which behaves the same everywhere, so `mock` would triple the
|
|
12
|
+
* pull-request time to re-assert identical wire traffic; and a normal dev
|
|
13
|
+
* machine has only chromium installed, so a `live` run that insisted on all
|
|
14
|
+
* three failed on a missing engine rather than on the code. Cross-browser
|
|
15
|
+
* rendering is worth checking deliberately, not on every run.
|
|
16
|
+
*/ const ALL_BROWSERS = [
|
|
17
|
+
{
|
|
18
|
+
name: 'chromium',
|
|
19
|
+
use: _extends({}, devices['Desktop Chrome'])
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'firefox',
|
|
23
|
+
use: _extends({}, devices['Desktop Firefox'])
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'webkit',
|
|
27
|
+
use: _extends({}, devices['Desktop Safari'])
|
|
28
|
+
}
|
|
29
|
+
];
|
|
30
|
+
const CHROMIUM_ONLY = ALL_BROWSERS.slice(0, 1);
|
|
31
|
+
/** Opts into firefox and webkit; needs `pnpm exec playwright install` first. */ const ALL_BROWSERS_VAR = 'E2E_BROWSERS';
|
|
32
|
+
/**
|
|
33
|
+
* The shared Playwright configuration for an entifix app e2e project.
|
|
34
|
+
*
|
|
35
|
+
* The profile decides three things, and specs decide none of them:
|
|
36
|
+
*
|
|
37
|
+
* - **which specs run** — by filename (`*.mock.spec.ts` / `*.live.spec.ts`).
|
|
38
|
+
* Selection by `testIgnore` rather than by an in-spec `test.skip` means a
|
|
39
|
+
* run with the wrong environment fails instead of quietly reporting green.
|
|
40
|
+
* - **the base URL** — the local app in `mock`; in `live` the app is expected
|
|
41
|
+
* to already be running (started with its real backend), so Playwright
|
|
42
|
+
* reuses it rather than racing a second one.
|
|
43
|
+
* - **whether a reused server is acceptable** — `mock` refuses a development
|
|
44
|
+
* one, `live` accepts whatever is there. Enforced by an auto fixture in
|
|
45
|
+
* `defineEntifixE2eTest`, not from here: Playwright loads `globalSetup`
|
|
46
|
+
* through a different module path than the one it uses for the config and the
|
|
47
|
+
* specs, and this package is `"type": "module"` while an app's
|
|
48
|
+
* `playwright.config.ts` is CJS — a file reached both ways transpiles for one
|
|
49
|
+
* and fails for the other. See `assertExpectedServer`.
|
|
50
|
+
*
|
|
51
|
+
* Browsers are chromium in both profiles unless `E2E_BROWSERS=all`.
|
|
52
|
+
*/ export const defineEntifixE2eConfig = ({ configFile, appDir, port, testDir = './src', readyPath = '', mockServerCommand, overrides = {} })=>{
|
|
53
|
+
var _process_env_BASE_URL;
|
|
54
|
+
const mock = isMockProfile();
|
|
55
|
+
const baseURL = (_process_env_BASE_URL = process.env['BASE_URL']) != null ? _process_env_BASE_URL : `http://localhost:${port}`;
|
|
56
|
+
return defineConfig(_extends({}, nxE2EPreset(configFile, {
|
|
57
|
+
testDir
|
|
58
|
+
}), {
|
|
59
|
+
// The other profile's specs are not skipped, they are not collected: a
|
|
60
|
+
// spec that cannot run here has nothing to say about this run.
|
|
61
|
+
testIgnore: mock ? '**/*.live.spec.ts' : '**/*.mock.spec.ts'
|
|
62
|
+
}, mock ? {} : {
|
|
63
|
+
timeout: 90000
|
|
64
|
+
}, {
|
|
65
|
+
use: {
|
|
66
|
+
baseURL,
|
|
67
|
+
trace: 'on-first-retry'
|
|
68
|
+
},
|
|
69
|
+
// Playwright starts the server itself, with `next start` rather than
|
|
70
|
+
// `nx run <app>:start`. An nx invocation here is inferred by
|
|
71
|
+
// `@nx/playwright/plugin` as a *continuous task dependency* of `e2e`, and
|
|
72
|
+
// the run then waits on a server that never signals completion — the e2e
|
|
73
|
+
// task never starts. The build the server needs is expressed instead as a
|
|
74
|
+
// plain `dependsOn` on the e2e target.
|
|
75
|
+
webServer: {
|
|
76
|
+
command: mock && mockServerCommand !== undefined ? mockServerCommand : `pnpm exec next start -p ${port}`,
|
|
77
|
+
cwd: join(workspaceRoot, appDir),
|
|
78
|
+
url: `${baseURL}${readyPath}`,
|
|
79
|
+
reuseExistingServer: true
|
|
80
|
+
},
|
|
81
|
+
projects: process.env[ALL_BROWSERS_VAR] === 'all' ? ALL_BROWSERS : CHROMIUM_ONLY
|
|
82
|
+
}, overrides));
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Re-exported so a Playwright suite reaches both from this entry point.
|
|
86
|
+
*
|
|
87
|
+
* ⚠️ Not only for convenience. `@nx/enforce-module-boundaries` treats a package
|
|
88
|
+
* that any file in the consuming project loads with a dynamic `import()` as
|
|
89
|
+
* lazy-loaded, and then refuses every *static* import of it — and
|
|
90
|
+
* `marketplace-app-e2e` has one: its msw preload must call `register()` for the
|
|
91
|
+
* resolver hook before it resolves anything, so its imports cannot be hoisted.
|
|
92
|
+
* The rule keys on the specifier, so a `live` spec there can reach
|
|
93
|
+
* `requireLiveUrl` through `/playwright` and not through the root entry.
|
|
94
|
+
*/ export { requireLiveUrl, resolveE2eProfile };
|
|
95
|
+
|
|
96
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/playwright/config.ts"],"sourcesContent":["import { join } from 'node:path';\n\nimport { workspaceRoot } from '@nx/devkit';\nimport { nxE2EPreset } from '@nx/playwright/preset';\nimport {\n defineConfig,\n devices,\n type PlaywrightTestConfig,\n} from '@playwright/test';\n\nimport {\n isMockProfile,\n requireLiveUrl,\n resolveE2eProfile,\n} from '../profile/profile.js';\n\nexport interface EntifixE2eConfigOptions {\n /** The playwright config file — pass `__filename`, as the Nx preset wants. */\n configFile: string;\n /**\n * The app's directory, relative to the workspace root, e.g.\n * `apps/back-office-app`. The server is started from there.\n */\n appDir: string;\n /** The port that app serves on (the `300N` convention). */\n port: number;\n /** Spec directory, relative to the config file. */\n testDir?: string;\n /**\n * Path Playwright polls to decide the server is up, relative to the base URL.\n *\n * A gated app needs one, and it must be **exempt from the auth middleware and\n * free of backend dependencies**: a cold probe against `/` gets a redirect to\n * a sign-in origin that is not running, and one against `/api/config` gets a\n * 500 until config-service is up. Either way the run dies on `Timed out\n * waiting for config.webServer` before a single spec starts. Defaults to the\n * base URL, which is right for an app with no gate.\n */\n readyPath?: string;\n /**\n * What Playwright runs to serve the app, when `next start` alone is not\n * enough.\n *\n * The one caller so far is the storefront, whose reads happen in **server\n * components**: `page.route()` cannot see a fetch the Next process makes, so\n * its `mock` profile launches the server under a `--import` preload that\n * installs msw inside that process instead. Expressed here rather than\n * through `overrides` so the cwd, the readiness URL and the reuse rule stay\n * in one place — an override would have to restate all three to change one.\n *\n * Ignored outside `mock`: a `live` run talks to real services and must not\n * start a faked one.\n */\n mockServerCommand?: string;\n /** Anything else to merge in, for a project with a genuine special case. */\n overrides?: PlaywrightTestConfig;\n}\n\n/**\n * Every browser Playwright can drive.\n *\n * Chromium is the default in **both** profiles. Interception happens through\n * `page.route()`, which behaves the same everywhere, so `mock` would triple the\n * pull-request time to re-assert identical wire traffic; and a normal dev\n * machine has only chromium installed, so a `live` run that insisted on all\n * three failed on a missing engine rather than on the code. Cross-browser\n * rendering is worth checking deliberately, not on every run.\n */\nconst ALL_BROWSERS = [\n { name: 'chromium', use: { ...devices['Desktop Chrome'] } },\n { name: 'firefox', use: { ...devices['Desktop Firefox'] } },\n { name: 'webkit', use: { ...devices['Desktop Safari'] } },\n];\n\nconst CHROMIUM_ONLY = ALL_BROWSERS.slice(0, 1);\n\n/** Opts into firefox and webkit; needs `pnpm exec playwright install` first. */\nconst ALL_BROWSERS_VAR = 'E2E_BROWSERS';\n\n/**\n * The shared Playwright configuration for an entifix app e2e project.\n *\n * The profile decides three things, and specs decide none of them:\n *\n * - **which specs run** — by filename (`*.mock.spec.ts` / `*.live.spec.ts`).\n * Selection by `testIgnore` rather than by an in-spec `test.skip` means a\n * run with the wrong environment fails instead of quietly reporting green.\n * - **the base URL** — the local app in `mock`; in `live` the app is expected\n * to already be running (started with its real backend), so Playwright\n * reuses it rather than racing a second one.\n * - **whether a reused server is acceptable** — `mock` refuses a development\n * one, `live` accepts whatever is there. Enforced by an auto fixture in\n * `defineEntifixE2eTest`, not from here: Playwright loads `globalSetup`\n * through a different module path than the one it uses for the config and the\n * specs, and this package is `\"type\": \"module\"` while an app's\n * `playwright.config.ts` is CJS — a file reached both ways transpiles for one\n * and fails for the other. See `assertExpectedServer`.\n *\n * Browsers are chromium in both profiles unless `E2E_BROWSERS=all`.\n */\nexport const defineEntifixE2eConfig = ({\n configFile,\n appDir,\n port,\n testDir = './src',\n readyPath = '',\n mockServerCommand,\n overrides = {},\n}: EntifixE2eConfigOptions): PlaywrightTestConfig => {\n const mock = isMockProfile();\n const baseURL = process.env['BASE_URL'] ?? `http://localhost:${port}`;\n\n return defineConfig({\n ...nxE2EPreset(configFile, { testDir }),\n // The other profile's specs are not skipped, they are not collected: a\n // spec that cannot run here has nothing to say about this run.\n testIgnore: mock ? '**/*.live.spec.ts' : '**/*.mock.spec.ts',\n // `live` pays for a real sign-in before its first assertion: `seedSession`\n // drives the provider's hosted login for real — three page loads across two\n // origins, each a Next app that hydrates before it will accept a keystroke.\n // Playwright's 30s default is spent on the fixture alone, and the failure it\n // produces points at whatever action was in flight rather than at the clock.\n // `mock` keeps the default: it fabricates the cookie and never leaves the app.\n ...(mock ? {} : { timeout: 90_000 }),\n use: {\n baseURL,\n trace: 'on-first-retry',\n },\n // Playwright starts the server itself, with `next start` rather than\n // `nx run <app>:start`. An nx invocation here is inferred by\n // `@nx/playwright/plugin` as a *continuous task dependency* of `e2e`, and\n // the run then waits on a server that never signals completion — the e2e\n // task never starts. The build the server needs is expressed instead as a\n // plain `dependsOn` on the e2e target.\n webServer: {\n command:\n mock && mockServerCommand !== undefined\n ? mockServerCommand\n : `pnpm exec next start -p ${port}`,\n cwd: join(workspaceRoot, appDir),\n url: `${baseURL}${readyPath}`,\n reuseExistingServer: true,\n },\n projects:\n process.env[ALL_BROWSERS_VAR] === 'all' ? ALL_BROWSERS : CHROMIUM_ONLY,\n ...overrides,\n });\n};\n\n/**\n * Re-exported so a Playwright suite reaches both from this entry point.\n *\n * ⚠️ Not only for convenience. `@nx/enforce-module-boundaries` treats a package\n * that any file in the consuming project loads with a dynamic `import()` as\n * lazy-loaded, and then refuses every *static* import of it — and\n * `marketplace-app-e2e` has one: its msw preload must call `register()` for the\n * resolver hook before it resolves anything, so its imports cannot be hoisted.\n * The rule keys on the specifier, so a `live` spec there can reach\n * `requireLiveUrl` through `/playwright` and not through the root entry.\n */\nexport { requireLiveUrl, resolveE2eProfile };\n"],"names":["join","workspaceRoot","nxE2EPreset","defineConfig","devices","isMockProfile","requireLiveUrl","resolveE2eProfile","ALL_BROWSERS","name","use","CHROMIUM_ONLY","slice","ALL_BROWSERS_VAR","defineEntifixE2eConfig","configFile","appDir","port","testDir","readyPath","mockServerCommand","overrides","process","mock","baseURL","env","testIgnore","timeout","trace","webServer","command","undefined","cwd","url","reuseExistingServer","projects"],"mappings":";AAAA,SAASA,IAAI,QAAQ,YAAY;AAEjC,SAASC,aAAa,QAAQ,aAAa;AAC3C,SAASC,WAAW,QAAQ,wBAAwB;AACpD,SACEC,YAAY,EACZC,OAAO,QAEF,mBAAmB;AAE1B,SACEC,aAAa,EACbC,cAAc,EACdC,iBAAiB,QACZ,wBAAwB;AA4C/B;;;;;;;;;CASC,GACD,MAAMC,eAAe;IACnB;QAAEC,MAAM;QAAYC,KAAK,aAAKN,OAAO,CAAC,iBAAiB;IAAG;IAC1D;QAAEK,MAAM;QAAWC,KAAK,aAAKN,OAAO,CAAC,kBAAkB;IAAG;IAC1D;QAAEK,MAAM;QAAUC,KAAK,aAAKN,OAAO,CAAC,iBAAiB;IAAG;CACzD;AAED,MAAMO,gBAAgBH,aAAaI,KAAK,CAAC,GAAG;AAE5C,8EAA8E,GAC9E,MAAMC,mBAAmB;AAEzB;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,MAAMC,yBAAyB,CAAC,EACrCC,UAAU,EACVC,MAAM,EACNC,IAAI,EACJC,UAAU,OAAO,EACjBC,YAAY,EAAE,EACdC,iBAAiB,EACjBC,YAAY,CAAC,CAAC,EACU;QAERC;IADhB,MAAMC,OAAOlB;IACb,MAAMmB,WAAUF,wBAAAA,QAAQG,GAAG,CAAC,WAAW,YAAvBH,wBAA2B,CAAC,iBAAiB,EAAEL,MAAM;IAErE,OAAOd,aAAa,aACfD,YAAYa,YAAY;QAAEG;IAAQ;QACrC,uEAAuE;QACvE,+DAA+D;QAC/DQ,YAAYH,OAAO,sBAAsB;OAOrCA,OAAO,CAAC,IAAI;QAAEI,SAAS;IAAO;QAClCjB,KAAK;YACHc;YACAI,OAAO;QACT;QACA,qEAAqE;QACrE,6DAA6D;QAC7D,0EAA0E;QAC1E,yEAAyE;QACzE,0EAA0E;QAC1E,uCAAuC;QACvCC,WAAW;YACTC,SACEP,QAAQH,sBAAsBW,YAC1BX,oBACA,CAAC,wBAAwB,EAAEH,MAAM;YACvCe,KAAKhC,KAAKC,eAAee;YACzBiB,KAAK,GAAGT,UAAUL,WAAW;YAC7Be,qBAAqB;QACvB;QACAC,UACEb,QAAQG,GAAG,CAACZ,iBAAiB,KAAK,QAAQL,eAAeG;OACxDU;AAEP,EAAE;AAEF;;;;;;;;;;CAUC,GACD,SAASf,cAAc,EAAEC,iBAAiB,GAAG"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type Locator, type Page } from '@playwright/test';
|
|
2
|
+
/** How a filter row is filled in. */
|
|
3
|
+
export interface FilterClause {
|
|
4
|
+
member: string;
|
|
5
|
+
operator: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SortClause {
|
|
9
|
+
member: string;
|
|
10
|
+
direction?: 'asc' | 'desc';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A driver for the `EntityTable` organism: filters, sorting, paging and the
|
|
14
|
+
* rendered rows.
|
|
15
|
+
*
|
|
16
|
+
* Every entity listing in the workspace is the same component, so its selectors
|
|
17
|
+
* belong in one place rather than being re-declared as local helpers in each
|
|
18
|
+
* suite — which is what the two admin specs did, with two different sets of
|
|
19
|
+
* conventions for the same widget.
|
|
20
|
+
*
|
|
21
|
+
* The wide (grid) layout is what is asserted on. Both layouts always render —
|
|
22
|
+
* the pivot is CSS-only, so there is no SSR hydration mismatch — and the table
|
|
23
|
+
* is the one carrying column semantics.
|
|
24
|
+
*/
|
|
25
|
+
export declare class EntityTablePage {
|
|
26
|
+
private readonly page;
|
|
27
|
+
constructor(page: Page);
|
|
28
|
+
/** Rows of the wide layout. */
|
|
29
|
+
get rows(): Locator;
|
|
30
|
+
/** Waits until the listing has painted at least one row. */
|
|
31
|
+
waitForRows(): Promise<void>;
|
|
32
|
+
/** Column headers, in render order. */
|
|
33
|
+
headers(): Promise<string[]>;
|
|
34
|
+
/**
|
|
35
|
+
* The values of one column, addressed by its header label rather than by
|
|
36
|
+
* position: a column added to the entity — or reordered by the user's saved
|
|
37
|
+
* preferences — must not silently shift what a spec is asserting on.
|
|
38
|
+
*/
|
|
39
|
+
columnValues(header: string): Promise<string[]>;
|
|
40
|
+
/** The distinct values of a column, sorted — the usual assertion subject. */
|
|
41
|
+
distinctColumnValues(header: string): Promise<string[]>;
|
|
42
|
+
openFilters(): Promise<void>;
|
|
43
|
+
/** `and` (default) or `or` across the rows of the panel. */
|
|
44
|
+
matchAny(match: 'and' | 'or'): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Adds a filter row and fills it in.
|
|
47
|
+
*
|
|
48
|
+
* The member is always selected explicitly, never left at the default: a new
|
|
49
|
+
* row defaults to the entity's *first filterable* member, so a spec relying
|
|
50
|
+
* on it would break the moment a member is declared ahead of that one.
|
|
51
|
+
*/
|
|
52
|
+
addFilter({ member, operator, value }: FilterClause): Promise<void>;
|
|
53
|
+
/** Filtering is emitted on Apply, not per keystroke — each emission is a request. */
|
|
54
|
+
applyFilters(): Promise<void>;
|
|
55
|
+
clearFilters(): Promise<void>;
|
|
56
|
+
/** Opens the panel, adds every clause, applies. */
|
|
57
|
+
filterBy(...clauses: FilterClause[]): Promise<void>;
|
|
58
|
+
openSorting(): Promise<void>;
|
|
59
|
+
addSort({ member, direction }: SortClause): Promise<void>;
|
|
60
|
+
applySorting(): Promise<void>;
|
|
61
|
+
/** Opens the panel, adds every term in precedence order, applies. */
|
|
62
|
+
sortBy(...clauses: SortClause[]): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* `exact` matters: Next.js' dev-tools button also matches a loose "Siguiente".
|
|
65
|
+
*/
|
|
66
|
+
nextPage(): Promise<void>;
|
|
67
|
+
previousPage(): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=entity-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-table.d.ts","sourceRoot":"","sources":["../../src/playwright/entity-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEnE,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAEvC,+BAA+B;IAC/B,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,4DAA4D;IACtD,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlC,uCAAuC;IACjC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIlC;;;;OAIG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAcrD,6EAA6E;IACvE,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAMvD,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,4DAA4D;IACtD,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlD;;;;;;OAMG;IACG,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAczE,qFAAqF;IAC/E,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC,mDAAmD;IAC7C,QAAQ,CAAC,GAAG,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnD,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,OAAO,CAAC,EAAE,MAAM,EAAE,SAAiB,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAajE,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC,qEAAqE;IAC/D,MAAM,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAMzB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;CAKpC"}
|