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.54.1"; 31 32 src = fetchFromGitHub { 33 owner = "Microsoft"; 34 repo = "playwright"; 35 rev = "v${version}"; 36 hash = "sha256-xwyREgelHLkpbUXOZTppKK7L6dE4jx0d/lbDWSKGzTY="; 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-InwWYRk6eRF62qI6qpVaPceIetSr3kPIBK4LdfeoJdo="; 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-gEm2oTxj4QIiGnIOPffOLh3BYSngpGToF89ObnDYBqs="; 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-c0UZ0Jg86icwJp3xarpXpxWjRYeIjz9wpWtJZDHkd8U="; 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-4bsX8Q8V3CBpIsyqMYTzfERQQPY5zlPf7CoqR6UkUHU="; 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\./,/^[[:space:]]*}$/d' utils/build/build.js 107 sed -i '/execSync/d' ./utils/generate_third_party_notice.js 108 chmod +w packages/playwright/bundles/babel 109 ln -s ${babel-bundle}/node_modules packages/playwright/bundles/babel/node_modules 110 chmod +w packages/playwright/bundles/expect 111 ln -s ${expect-bundle}/node_modules packages/playwright/bundles/expect/node_modules 112 chmod +w packages/playwright/bundles/utils 113 ln -s ${utils-bundle}/node_modules packages/playwright/bundles/utils/node_modules 114 chmod +w packages/playwright-core/bundles/utils 115 ln -s ${utils-bundle-core}/node_modules packages/playwright-core/bundles/utils/node_modules 116 chmod +w packages/playwright-core/bundles/zip 117 ln -s ${zip-bundle}/node_modules packages/playwright-core/bundles/zip/node_modules 118 ''; 119 120 installPhase = '' 121 runHook preInstall 122 123 shopt -s extglob 124 125 mkdir -p "$out/lib" 126 cp -r packages/playwright/node_modules "$out/lib/node_modules" 127 128 mkdir -p "$out/lib/node_modules/playwright" 129 cp -r packages/playwright/!(bundles|src|node_modules|.*) "$out/lib/node_modules/playwright" 130 131 # for not supported platforms (such as NixOS) playwright assumes that it runs on ubuntu-20.04 132 # that forces it to use overridden webkit revision 133 # let's remove that override to make it use latest revision provided in Nixpkgs 134 # https://github.com/microsoft/playwright/blob/baeb065e9ea84502f347129a0b896a85d2a8dada/packages/playwright-core/src/server/utils/hostPlatform.ts#L111 135 jq '(.browsers[] | select(.name == "webkit") | .revisionOverrides) |= del(."ubuntu20.04-x64", ."ubuntu20.04-arm64")' \ 136 packages/playwright-core/browsers.json > browser.json.tmp && mv browser.json.tmp packages/playwright-core/browsers.json 137 mkdir -p "$out/lib/node_modules/playwright-core" 138 cp -r packages/playwright-core/!(bundles|src|bin|.*) "$out/lib/node_modules/playwright-core" 139 140 mkdir -p "$out/lib/node_modules/@playwright/test" 141 cp -r packages/playwright-test/* "$out/lib/node_modules/@playwright/test" 142 143 runHook postInstall 144 ''; 145 146 meta = { 147 description = "Framework for Web Testing and Automation"; 148 homepage = "https://playwright.dev"; 149 license = lib.licenses.asl20; 150 maintainers = with lib.maintainers; [ 151 kalekseev 152 marie 153 ]; 154 inherit (nodejs.meta) platforms; 155 }; 156 }; 157 158 playwright-core = stdenv.mkDerivation (finalAttrs: { 159 pname = "playwright-core"; 160 inherit (playwright) version src meta; 161 162 installPhase = '' 163 runHook preInstall 164 165 cp -r ${playwright}/lib/node_modules/playwright-core "$out" 166 167 runHook postInstall 168 ''; 169 170 passthru = { 171 browsersJSON = (lib.importJSON ./browsers.json).browsers; 172 browsers = browsers { }; 173 browsers-chromium = browsers { 174 withFirefox = false; 175 withWebkit = false; 176 withChromiumHeadlessShell = false; 177 }; 178 inherit components; 179 }; 180 }); 181 182 playwright-test = stdenv.mkDerivation (finalAttrs: { 183 pname = "playwright-test"; 184 inherit (playwright) version src; 185 186 nativeBuildInputs = [ makeWrapper ]; 187 installPhase = '' 188 runHook preInstall 189 190 shopt -s extglob 191 mkdir -p $out/bin 192 cp -r ${playwright}/* $out 193 194 makeWrapper "${nodejs}/bin/node" "$out/bin/playwright" \ 195 --add-flags "$out/lib/node_modules/@playwright/test/cli.js" \ 196 --prefix NODE_PATH : ${placeholder "out"}/lib/node_modules \ 197 --set-default PLAYWRIGHT_BROWSERS_PATH "${playwright-core.passthru.browsers}" 198 199 runHook postInstall 200 ''; 201 202 meta = playwright.meta // { 203 mainProgram = "playwright"; 204 }; 205 }); 206 207 components = { 208 chromium = callPackage ./chromium.nix { 209 inherit suffix system throwSystem; 210 inherit (playwright-core.passthru.browsersJSON.chromium) revision; 211 fontconfig_file = makeFontsConf { 212 fontDirectories = [ ]; 213 }; 214 }; 215 chromium-headless-shell = callPackage ./chromium-headless-shell.nix { 216 inherit suffix system throwSystem; 217 inherit (playwright-core.passthru.browsersJSON.chromium) revision; 218 }; 219 firefox = callPackage ./firefox.nix { 220 inherit suffix system throwSystem; 221 inherit (playwright-core.passthru.browsersJSON.firefox) revision; 222 }; 223 webkit = callPackage ./webkit.nix { 224 inherit suffix system throwSystem; 225 inherit (playwright-core.passthru.browsersJSON.webkit) revision; 226 }; 227 ffmpeg = callPackage ./ffmpeg.nix { 228 inherit suffix system throwSystem; 229 inherit (playwright-core.passthru.browsersJSON.ffmpeg) revision; 230 }; 231 }; 232 233 browsers = lib.makeOverridable ( 234 { 235 withChromium ? true, 236 withFirefox ? true, 237 withWebkit ? true, # may require `export PLAYWRIGHT_HOST_PLATFORM_OVERRIDE="ubuntu-24.04"` 238 withFfmpeg ? true, 239 withChromiumHeadlessShell ? true, 240 fontconfig_file ? makeFontsConf { 241 fontDirectories = [ ]; 242 }, 243 }: 244 let 245 browsers = 246 lib.optionals withChromium [ "chromium" ] 247 ++ lib.optionals withChromiumHeadlessShell [ "chromium-headless-shell" ] 248 ++ lib.optionals withFirefox [ "firefox" ] 249 ++ lib.optionals withWebkit [ "webkit" ] 250 ++ lib.optionals withFfmpeg [ "ffmpeg" ]; 251 in 252 linkFarm "playwright-browsers" ( 253 lib.listToAttrs ( 254 map ( 255 name: 256 let 257 revName = if name == "chromium-headless-shell" then "chromium" else name; 258 value = playwright-core.passthru.browsersJSON.${revName}; 259 in 260 lib.nameValuePair 261 # TODO check platform for revisionOverrides 262 "${lib.replaceStrings [ "-" ] [ "_" ] name}-${value.revision}" 263 components.${name} 264 ) browsers 265 ) 266 ) 267 ); 268in 269{ 270 playwright-core = playwright-core; 271 playwright-test = playwright-test; 272}