@saucebase/laravel-playwright 2.0.1 → 2.2.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/README.md CHANGED
@@ -93,20 +93,30 @@ export default defineConfig<LaravelOptions>({
93
93
 
94
94
  Run the suite on its own server and database, so it never touches your dev app or its data. This works the same however you serve the app day to day: Herd, Valet, Sail, Docker or `artisan serve`.
95
95
 
96
- **1. Create `.env.e2e`.** Copy `.env` and give it its own database and port:
96
+ **1. Create `.env.e2e`:**
97
+
98
+ ```bash
99
+ php artisan playwright:env
100
+ ```
101
+
102
+ This writes a copy of your `.env` with its own server and database. Laravel loads one env file, not one on top of another, so the copy keeps everything else your app needs (`APP_KEY`, secrets, mail). Only these change:
97
103
 
98
104
  ```dotenv
99
105
  APP_ENV=e2e
100
106
  APP_URL=http://localhost:8100
101
107
  DB_CONNECTION=sqlite
108
+ DB_URL="sqlite:///database/e2e.sqlite?transaction_mode=IMMEDIATE&busy_timeout=10000"
102
109
  DB_DATABASE=database/e2e.sqlite
103
110
  SESSION_DRIVER=file
104
111
  CACHE_STORE=file
105
112
  QUEUE_CONNECTION=sync
106
113
  MAIL_MAILER=log
114
+ REDIS_PREFIX=<your prefix>e2e_
107
115
  ```
108
116
 
109
- Keep `.env.e2e` out of git like `.env`.
117
+ `DB_URL` carries the SQLite settings that let parallel workers wait for each other. `transaction_mode=IMMEDIATE` needs PHP 8.4 or later; older versions ignore it, so read-then-write transactions can still hit `database is locked`. `busy_timeout` applies on every version.
118
+
119
+ Options: `php artisan playwright:env <environment> --url=http://localhost:9000 --force`. Edit the file afterwards for anything else the suite needs. Keep `.env.e2e` out of git like `.env`, and in CI, run the command after creating `.env`.
110
120
 
111
121
  **2. Let Playwright start the server:**
112
122
 
@@ -1,16 +1,16 @@
1
1
  import { test as h } from "@playwright/test";
2
- import { existsSync as p, readFileSync as u } from "node:fs";
3
- import { join as v } from "node:path";
2
+ import { existsSync as p, readFileSync as v } from "node:fs";
3
+ import { join as u } from "node:path";
4
4
  import { parseEnv as w } from "node:util";
5
5
  function m(s = {}) {
6
- const { env: t = "e2e", host: e = "127.0.0.1", workers: a = 4, cwd: r = process.cwd(), migrate: n = !0 } = s, o = v(r, `.env.${t}`);
6
+ const { env: t = "e2e", host: e = "127.0.0.1", workers: a = 4, cwd: r = process.cwd(), migrate: n = !0 } = s, o = u(r, `.env.${t}`);
7
7
  if (!p(o))
8
- throw new Error(`laravelServer: create .env.${t} in ${r}, with its own database, before running the suite.`);
8
+ throw new Error(`laravelServer: .env.${t} is missing in ${r}. Create it with \`php artisan playwright:env${t === "e2e" ? "" : ` ${t}`}\` (a copy of .env with its own server and database).`);
9
9
  if (process.env.APP_ENV !== void 0 && process.env.APP_ENV !== t)
10
10
  throw new Error(
11
11
  `laravelServer: the Playwright process has APP_ENV=${process.env.APP_ENV}, so another env file was loaded and its values would override .env.${t}. Load .env.${t} instead (dotenv config({ path: '.env.${t}' })) or none.`
12
12
  );
13
- const i = w(u(o, "utf8")).APP_URL;
13
+ const i = w(v(o, "utf8")).APP_URL;
14
14
  if (!i)
15
15
  throw new Error(`laravelServer: set APP_URL in .env.${t}, e.g. http://localhost:8100.`);
16
16
  const c = new URL(i);
@@ -1,4 +1,4 @@
1
- (function(n,l){typeof exports=="object"&&typeof module<"u"?l(exports,require("@playwright/test"),require("node:fs"),require("node:path"),require("node:util")):typeof define=="function"&&define.amd?define(["exports","@playwright/test","node:fs","node:path","node:util"],l):(n=typeof globalThis<"u"?globalThis:n||self,l(n.LaravelPlaywright={},n.PlaywrightTest,n.node_fs,n.node_path,n.node_util))})(this,(function(n,l,p,d,f){"use strict";function y(o={}){const{env:e="e2e",host:t="127.0.0.1",workers:a=4,cwd:r=process.cwd(),migrate:s=!0}=o,i=d.join(r,`.env.${e}`);if(!p.existsSync(i))throw new Error(`laravelServer: create .env.${e} in ${r}, with its own database, before running the suite.`);if(process.env.APP_ENV!==void 0&&process.env.APP_ENV!==e)throw new Error(`laravelServer: the Playwright process has APP_ENV=${process.env.APP_ENV}, so another env file was loaded and its values would override .env.${e}. Load .env.${e} instead (dotenv config({ path: '.env.${e}' })) or none.`);const c=f.parseEnv(p.readFileSync(i,"utf8")).APP_URL;if(!c)throw new Error(`laravelServer: set APP_URL in .env.${e}, e.g. http://localhost:8100.`);const u=new URL(c);if(u.protocol!=="http:")throw new Error(`laravelServer: APP_URL in .env.${e} must be http: (artisan serve has no TLS), got ${c}.`);return{command:[s&&`php artisan migrate --env=${e} --force`,`php artisan serve --env=${e} --host=${t} --port=${u.port||80} --no-reload`].filter(Boolean).join(" && "),url:u.origin,cwd:r,env:{APP_ENV:e,PHP_CLI_SERVER_WORKERS:String(a),APP_CONFIG_CACHE:`bootstrap/cache/${e}/config.php`,APP_ROUTES_CACHE:`bootstrap/cache/${e}/routes.php`,APP_EVENTS_CACHE:`bootstrap/cache/${e}/events.php`},reuseExistingServer:!process.env.CI}}function v(o,e){if(!e)return!1;const t=new URL(e).hostname;return o.hostname===t||o.hostname.endsWith(`.${t}`)}const h="X-Playwright-Test",P=l.test.extend({laravelBaseUrl:[void 0,{option:!0}],laravelSecret:[void 0,{option:!0}],laravelIsAppUrl:[void 0,{option:!0}],laravelTestId:async({},o)=>{await o(crypto.randomUUID())},context:async({context:o,baseURL:e,laravelIsAppUrl:t,laravelTestId:a},r)=>{const s=t??(i=>v(i,e));await o.route(s,i=>i.fallback({headers:{...i.request().headers(),[h]:a}})),await r(o)},laravel:async({laravelBaseUrl:o,laravelSecret:e,laravelTestId:t,baseURL:a,request:r},s)=>{const i=o||a+"/playwright",c=new w(i,r,e,t);await s(c),await c.tearDown()}});class w{constructor(e,t,a=void 0,r=crypto.randomUUID()){this.baseUrl=e,this.request=t,this.secret=a,this.testId=r}async call(e,t={}){const a=this.baseUrl.replace(/\/$/,"")+e,r={Accept:"application/json",[h]:this.testId};this.secret&&(r["X-Playwright-Secret"]=this.secret);const s=await this.request.post(a,{data:t,headers:r});if(s.status()!==200)throw new Error(`
1
+ (function(n,l){typeof exports=="object"&&typeof module<"u"?l(exports,require("@playwright/test"),require("node:fs"),require("node:path"),require("node:util")):typeof define=="function"&&define.amd?define(["exports","@playwright/test","node:fs","node:path","node:util"],l):(n=typeof globalThis<"u"?globalThis:n||self,l(n.LaravelPlaywright={},n.PlaywrightTest,n.node_fs,n.node_path,n.node_util))})(this,(function(n,l,p,d,f){"use strict";function y(i={}){const{env:e="e2e",host:t="127.0.0.1",workers:a=4,cwd:r=process.cwd(),migrate:s=!0}=i,o=d.join(r,`.env.${e}`);if(!p.existsSync(o))throw new Error(`laravelServer: .env.${e} is missing in ${r}. Create it with \`php artisan playwright:env${e==="e2e"?"":` ${e}`}\` (a copy of .env with its own server and database).`);if(process.env.APP_ENV!==void 0&&process.env.APP_ENV!==e)throw new Error(`laravelServer: the Playwright process has APP_ENV=${process.env.APP_ENV}, so another env file was loaded and its values would override .env.${e}. Load .env.${e} instead (dotenv config({ path: '.env.${e}' })) or none.`);const c=f.parseEnv(p.readFileSync(o,"utf8")).APP_URL;if(!c)throw new Error(`laravelServer: set APP_URL in .env.${e}, e.g. http://localhost:8100.`);const u=new URL(c);if(u.protocol!=="http:")throw new Error(`laravelServer: APP_URL in .env.${e} must be http: (artisan serve has no TLS), got ${c}.`);return{command:[s&&`php artisan migrate --env=${e} --force`,`php artisan serve --env=${e} --host=${t} --port=${u.port||80} --no-reload`].filter(Boolean).join(" && "),url:u.origin,cwd:r,env:{APP_ENV:e,PHP_CLI_SERVER_WORKERS:String(a),APP_CONFIG_CACHE:`bootstrap/cache/${e}/config.php`,APP_ROUTES_CACHE:`bootstrap/cache/${e}/routes.php`,APP_EVENTS_CACHE:`bootstrap/cache/${e}/events.php`},reuseExistingServer:!process.env.CI}}function v(i,e){if(!e)return!1;const t=new URL(e).hostname;return i.hostname===t||i.hostname.endsWith(`.${t}`)}const h="X-Playwright-Test",P=l.test.extend({laravelBaseUrl:[void 0,{option:!0}],laravelSecret:[void 0,{option:!0}],laravelIsAppUrl:[void 0,{option:!0}],laravelTestId:async({},i)=>{await i(crypto.randomUUID())},context:async({context:i,baseURL:e,laravelIsAppUrl:t,laravelTestId:a},r)=>{const s=t??(o=>v(o,e));await i.route(s,o=>o.fallback({headers:{...o.request().headers(),[h]:a}})),await r(i)},laravel:async({laravelBaseUrl:i,laravelSecret:e,laravelTestId:t,baseURL:a,request:r},s)=>{const o=i||a+"/playwright",c=new w(o,r,e,t);await s(c),await c.tearDown()}});class w{constructor(e,t,a=void 0,r=crypto.randomUUID()){this.baseUrl=e,this.request=t,this.secret=a,this.testId=r}async call(e,t={}){const a=this.baseUrl.replace(/\/$/,"")+e,r={Accept:"application/json",[h]:this.testId};this.secret&&(r["X-Playwright-Secret"]=this.secret);const s=await this.request.post(a,{data:t,headers:r});if(s.status()!==200)throw new Error(`
2
2
  Failed to call Laravel ${e}.
3
3
  Status: ${s.status()}
4
4
  Response: ${await s.text()}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saucebase/laravel-playwright",
3
- "version": "v2.0.1",
3
+ "version": "v2.2.0",
4
4
  "description": "Blends Laravel and Playwright into seamless E2E tests — factories, queries, artisan commands, and time travel.",
5
5
  "license": "MIT",
6
6
  "repository": {