1{
2 lib,
3 buildNpmPackage,
4 stdenv,
5 chromium,
6 ffmpeg,
7 jq,
8 nodejs,
9 fetchFromGitHub,
10 linkFarm,
11 callPackage,
12 makeFontsConf,
13 makeWrapper,
14 runCommand,
15 cacert,
16}:
17let
18 inherit (stdenv.hostPlatform) system;
19
20 throwSystem = throw "Unsupported system: ${system}";
21 suffix =
22 {
23 x86_64-linux = "linux";
24 aarch64-linux = "linux-arm64";
25 x86_64-darwin = "mac";
26 aarch64-darwin = "mac-arm64";
27 }
28 .${system} or throwSystem;
29
30 version = "1.52.0";
31
32 src = fetchFromGitHub {
33 owner = "Microsoft";
34 repo = "playwright";
35 rev = "v${version}";
36 hash = "sha256-+2ih1tZHqbNtyabtYi1Sd3f9Qs3Is8zUMNBt6Lo2IKs=";
37 };
38
39 babel-bundle = buildNpmPackage {
40 pname = "babel-bundle";
41 inherit version src;
42 sourceRoot = "${src.name}/packages/playwright/bundles/babel";
43 npmDepsHash = "sha256-sdl+rMCmuOmY1f7oSfGuAAFCiPCFzqkQtFCncL4o5LQ=";
44 dontNpmBuild = true;
45 installPhase = ''
46 cp -r . "$out"
47 '';
48 };
49 expect-bundle = buildNpmPackage {
50 pname = "expect-bundle";
51 inherit version src;
52 sourceRoot = "${src.name}/packages/playwright/bundles/expect";
53 npmDepsHash = "sha256-KwxNqPefvPPHG4vbco2O4G8WlA7l33toJdfNWHMTDOQ=";
54 dontNpmBuild = true;
55 installPhase = ''
56 cp -r . "$out"
57 '';
58 };
59 utils-bundle = buildNpmPackage {
60 pname = "utils-bundle";
61 inherit version src;
62 sourceRoot = "${src.name}/packages/playwright/bundles/utils";
63 npmDepsHash = "sha256-tyk9bv1ethQSm8PKDpLthwsmqJugLIpsUOf9G8TOKRc=";
64 dontNpmBuild = true;
65 installPhase = ''
66 cp -r . "$out"
67 '';
68 };
69 utils-bundle-core = buildNpmPackage {
70 pname = "utils-bundle-core";
71 inherit version src;
72 sourceRoot = "${src.name}/packages/playwright-core/bundles/utils";
73 npmDepsHash = "sha256-3hdOmvs/IGAgW7vhldms9Q9/ZQfbjbc+xP+JEtGJ7g8=";
74 dontNpmBuild = true;
75 installPhase = ''
76 cp -r . "$out"
77 '';
78 };
79 zip-bundle = buildNpmPackage {
80 pname = "zip-bundle";
81 inherit version src;
82 sourceRoot = "${src.name}/packages/playwright-core/bundles/zip";
83 npmDepsHash = "sha256-62Apz8uX6d4HKDqQxR6w5Vs31tl63McWGPwT6s2YsBE=";
84 dontNpmBuild = true;
85 installPhase = ''
86 cp -r . "$out"
87 '';
88 };
89
90 playwright = buildNpmPackage {
91 pname = "playwright";
92 inherit version src;
93
94 sourceRoot = "${src.name}"; # update.sh depends on sourceRoot presence
95 npmDepsHash = "sha256-Os/HvvL+CFFb2sM+EDdxF2hN28Sg7oy3vBBfkIipkqs=";
96
97 nativeBuildInputs = [
98 cacert
99 jq
100 ];
101
102 ELECTRON_SKIP_BINARY_DOWNLOAD = true;
103
104 postPatch = ''
105 sed -i '/\/\/ Update test runner./,/^\s*$/{d}' utils/build/build.js
106 sed -i '/\/\/ Update bundles./,/^\s*$/{d}' utils/build/build.js
107 sed -i '/execSync/d' ./utils/generate_third_party_notice.js
108 sed -i '/plugins: /d' ./packages/playwright/bundles/utils/build.js
109 sed -i '/plugins: /d' ./packages/playwright-core/bundles/zip/build.js
110 chmod +w packages/playwright/bundles/babel
111 ln -s ${babel-bundle}/node_modules packages/playwright/bundles/babel/node_modules
112 chmod +w packages/playwright/bundles/expect
113 ln -s ${expect-bundle}/node_modules packages/playwright/bundles/expect/node_modules
114 chmod +w packages/playwright/bundles/utils
115 ln -s ${utils-bundle}/node_modules packages/playwright/bundles/utils/node_modules
116 chmod +w packages/playwright-core/bundles/utils
117 ln -s ${utils-bundle-core}/node_modules packages/playwright-core/bundles/utils/node_modules
118 chmod +w packages/playwright-core/bundles/zip
119 ln -s ${zip-bundle}/node_modules packages/playwright-core/bundles/zip/node_modules
120 '';
121
122 installPhase = ''
123 runHook preInstall
124
125 shopt -s extglob
126
127 mkdir -p "$out/lib"
128 cp -r packages/playwright/node_modules "$out/lib/node_modules"
129
130 mkdir -p "$out/lib/node_modules/playwright"
131 cp -r packages/playwright/!(bundles|src|node_modules|.*) "$out/lib/node_modules/playwright"
132
133 # for not supported platforms (such as NixOS) playwright assumes that it runs on ubuntu-20.04
134 # that forces it to use overridden webkit revision
135 # let's remove that override to make it use latest revision provided in Nixpkgs
136 # https://github.com/microsoft/playwright/blob/baeb065e9ea84502f347129a0b896a85d2a8dada/packages/playwright-core/src/server/utils/hostPlatform.ts#L111
137 jq '(.browsers[] | select(.name == "webkit") | .revisionOverrides) |= del(."ubuntu20.04-x64", ."ubuntu20.04-arm64")' \
138 packages/playwright-core/browsers.json > browser.json.tmp && mv browser.json.tmp packages/playwright-core/browsers.json
139 mkdir -p "$out/lib/node_modules/playwright-core"
140 cp -r packages/playwright-core/!(bundles|src|bin|.*) "$out/lib/node_modules/playwright-core"
141
142 mkdir -p "$out/lib/node_modules/@playwright/test"
143 cp -r packages/playwright-test/* "$out/lib/node_modules/@playwright/test"
144
145 runHook postInstall
146 '';
147
148 meta = {
149 description = "Framework for Web Testing and Automation";
150 homepage = "https://playwright.dev";
151 license = lib.licenses.asl20;
152 maintainers = with lib.maintainers; [
153 kalekseev
154 marie
155 ];
156 inherit (nodejs.meta) platforms;
157 };
158 };
159
160 playwright-core = stdenv.mkDerivation (finalAttrs: {
161 pname = "playwright-core";
162 inherit (playwright) version src meta;
163
164 installPhase = ''
165 runHook preInstall
166
167 cp -r ${playwright}/lib/node_modules/playwright-core "$out"
168
169 runHook postInstall
170 '';
171
172 passthru = {
173 browsersJSON = (lib.importJSON ./browsers.json).browsers;
174 browsers = browsers { };
175 browsers-chromium = browsers {
176 withFirefox = false;
177 withWebkit = false;
178 withChromiumHeadlessShell = false;
179 };
180 inherit components;
181 };
182 });
183
184 playwright-test = stdenv.mkDerivation (finalAttrs: {
185 pname = "playwright-test";
186 inherit (playwright) version src;
187
188 nativeBuildInputs = [ makeWrapper ];
189 installPhase = ''
190 runHook preInstall
191
192 shopt -s extglob
193 mkdir -p $out/bin
194 cp -r ${playwright}/* $out
195
196 makeWrapper "${nodejs}/bin/node" "$out/bin/playwright" \
197 --add-flags "$out/lib/node_modules/@playwright/test/cli.js" \
198 --prefix NODE_PATH : ${placeholder "out"}/lib/node_modules \
199 --set-default PLAYWRIGHT_BROWSERS_PATH "${playwright-core.passthru.browsers}"
200
201 runHook postInstall
202 '';
203
204 meta = playwright.meta // {
205 mainProgram = "playwright";
206 };
207 });
208
209 components = {
210 chromium = callPackage ./chromium.nix {
211 inherit suffix system throwSystem;
212 inherit (playwright-core.passthru.browsersJSON.chromium) revision;
213 fontconfig_file = makeFontsConf {
214 fontDirectories = [ ];
215 };
216 };
217 chromium-headless-shell = callPackage ./chromium-headless-shell.nix {
218 inherit suffix system throwSystem;
219 inherit (playwright-core.passthru.browsersJSON.chromium) revision;
220 };
221 firefox = callPackage ./firefox.nix {
222 inherit suffix system throwSystem;
223 inherit (playwright-core.passthru.browsersJSON.firefox) revision;
224 };
225 webkit = callPackage ./webkit.nix {
226 inherit suffix system throwSystem;
227 inherit (playwright-core.passthru.browsersJSON.webkit) revision;
228 };
229 ffmpeg = callPackage ./ffmpeg.nix {
230 inherit suffix system throwSystem;
231 inherit (playwright-core.passthru.browsersJSON.ffmpeg) revision;
232 };
233 };
234
235 browsers = lib.makeOverridable (
236 {
237 withChromium ? true,
238 withFirefox ? true,
239 withWebkit ? true, # may require `export PLAYWRIGHT_HOST_PLATFORM_OVERRIDE="ubuntu-24.04"`
240 withFfmpeg ? true,
241 withChromiumHeadlessShell ? true,
242 fontconfig_file ? makeFontsConf {
243 fontDirectories = [ ];
244 },
245 }:
246 let
247 browsers =
248 lib.optionals withChromium [ "chromium" ]
249 ++ lib.optionals withChromiumHeadlessShell [ "chromium-headless-shell" ]
250 ++ lib.optionals withFirefox [ "firefox" ]
251 ++ lib.optionals withWebkit [ "webkit" ]
252 ++ lib.optionals withFfmpeg [ "ffmpeg" ];
253 in
254 linkFarm "playwright-browsers" (
255 lib.listToAttrs (
256 map (
257 name:
258 let
259 revName = if name == "chromium-headless-shell" then "chromium" else name;
260 value = playwright-core.passthru.browsersJSON.${revName};
261 in
262 lib.nameValuePair
263 # TODO check platform for revisionOverrides
264 "${lib.replaceStrings [ "-" ] [ "_" ] name}-${value.revision}"
265 components.${name}
266 ) browsers
267 )
268 )
269 );
270in
271{
272 playwright-core = playwright-core;
273 playwright-test = playwright-test;
274}