@@ -2,11 +2,13 @@ import assert from "node:assert";
22import { mkdir , readFile , writeFile } from "node:fs/promises" ;
33import path from "node:path" ;
44import dedent from "ts-dedent" ;
5+ import { vi } from "vitest" ;
56import { bundleWorker } from "../deployment-bundle/bundle" ;
67import { noopModuleCollector } from "../deployment-bundle/module-collection" ;
78import { isNavigatorDefined } from "../navigator-user-agent" ;
89import { mockConsoleMethods } from "./helpers/mock-console" ;
910import { runInTempDir } from "./helpers/run-in-tmp" ;
11+ import type { BundleOptions } from "../deployment-bundle/bundle" ;
1012
1113/*
1214 * This file contains inline comments with the word "javascript"
@@ -82,8 +84,25 @@ describe("isNavigatorDefined", () => {
8284describe ( "defineNavigatorUserAgent is respected" , ( ) => {
8385 runInTempDir ( ) ;
8486 const std = mockConsoleMethods ( ) ;
87+ const sharedBundleOptions = {
88+ bundle : true ,
89+ additionalModules : [ ] ,
90+ moduleCollector : noopModuleCollector ,
91+ doBindings : [ ] ,
92+ workflowBindings : [ ] ,
93+ define : { } ,
94+ alias : { } ,
95+ checkFetch : false ,
96+ targetConsumer : "deploy" ,
97+ local : true ,
98+ projectRoot : process . cwd ( ) ,
99+ } satisfies Partial < BundleOptions > ;
100+
101+ afterEach ( ( ) => {
102+ vi . unstubAllEnvs ( ) ;
103+ } ) ;
85104
86- it ( "defineNavigatorUserAgent = false, navigator preserved " , async ( ) => {
105+ it ( "preserves `navigator` when `defineNavigatorUserAgent` is `false` " , async ( ) => {
87106 await seedFs ( {
88107 "src/index.js" : dedent /* javascript */ `
89108 function randomBytes(length) {
@@ -113,17 +132,7 @@ describe("defineNavigatorUserAgent is respected", () => {
113132 path . resolve ( "dist" ) ,
114133 // @ts -expect-error Ignore the requirement for passing undefined values
115134 {
116- bundle : true ,
117- additionalModules : [ ] ,
118- moduleCollector : noopModuleCollector ,
119- doBindings : [ ] ,
120- workflowBindings : [ ] ,
121- define : { } ,
122- alias : { } ,
123- checkFetch : false ,
124- targetConsumer : "deploy" ,
125- local : true ,
126- projectRoot : process . cwd ( ) ,
135+ ...sharedBundleOptions ,
127136 defineNavigatorUserAgent : false ,
128137 }
129138 ) ;
@@ -145,7 +154,7 @@ describe("defineNavigatorUserAgent is respected", () => {
145154 expect ( fileContents ) . toContain ( "navigator.userAgent" ) ;
146155 } ) ;
147156
148- it ( "defineNavigatorUserAgent = true, navigator treeshaken " , async ( ) => {
157+ it ( "tree shakes ` navigator` when `defineNavigatorUserAgent` is `true` " , async ( ) => {
149158 await seedFs ( {
150159 "src/index.js" : dedent /* javascript */ `
151160 function randomBytes(length) {
@@ -175,17 +184,53 @@ describe("defineNavigatorUserAgent is respected", () => {
175184 path . resolve ( "dist" ) ,
176185 // @ts -expect-error Ignore the requirement for passing undefined values
177186 {
178- bundle : true ,
179- additionalModules : [ ] ,
180- moduleCollector : noopModuleCollector ,
181- doBindings : [ ] ,
182- workflowBindings : [ ] ,
183- define : { } ,
184- alias : { } ,
185- checkFetch : false ,
186- targetConsumer : "deploy" ,
187- local : true ,
187+ ...sharedBundleOptions ,
188+ defineNavigatorUserAgent : true ,
189+ }
190+ ) ;
191+
192+ // Build time warning is suppressed, because esbuild treeshakes the relevant code path
193+ expect ( std . warn ) . toMatchInlineSnapshot ( `""` ) ;
194+
195+ const fileContents = await readFile ( "dist/index.js" , "utf8" ) ;
196+
197+ // navigator.userAgent should have been defined, and so should not be present in the bundle
198+ expect ( fileContents ) . not . toContain ( "navigator.userAgent" ) ;
199+ } ) ;
200+
201+ it ( "tree shakes `navigator` when `defineNavigatorUserAgent` is `true` and `process.env.NODE_ENV` is `undefined`" , async ( ) => {
202+ await seedFs ( {
203+ "src/index.js" : dedent /* javascript */ `
204+ function randomBytes(length) {
205+ if (navigator.userAgent !== "Cloudflare-Workers") {
206+ return new Uint8Array(require("node:crypto").randomBytes(length));
207+ } else {
208+ return crypto.getRandomValues(new Uint8Array(length));
209+ }
210+ }
211+ export default {
212+ async fetch(request, env) {
213+ return new Response(randomBytes(10))
214+ },
215+ };
216+ ` ,
217+ } ) ;
218+
219+ vi . stubEnv ( "NODE_ENV" , undefined ) ;
220+
221+ await bundleWorker (
222+ {
223+ file : path . resolve ( "src/index.js" ) ,
188224 projectRoot : process . cwd ( ) ,
225+ configPath : undefined ,
226+ format : "modules" ,
227+ moduleRoot : path . dirname ( path . resolve ( "src/index.js" ) ) ,
228+ exports : [ ] ,
229+ } ,
230+ path . resolve ( "dist" ) ,
231+ // @ts -expect-error Ignore the requirement for passing undefined values
232+ {
233+ ...sharedBundleOptions ,
189234 defineNavigatorUserAgent : true ,
190235 }
191236 ) ;
0 commit comments