@ledgerhq/device-mockserver-react 0.0.0-develop-20261105000842 → 0.0.0-develop-20261107000805

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.
Files changed (34) hide show
  1. package/lib/cjs/package.json +1 -1
  2. package/lib/esm/package.json +1 -1
  3. package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
  4. package/package.json +6 -6
  5. package/lib/cjs/src/DeviceOsInfo.test.js +0 -2
  6. package/lib/cjs/src/DeviceOsInfo.test.js.map +0 -7
  7. package/lib/cjs/src/DeviceScreen.test.js +0 -2
  8. package/lib/cjs/src/DeviceScreen.test.js.map +0 -7
  9. package/lib/cjs/src/DeviceScreenButtons.test.js +0 -2
  10. package/lib/cjs/src/DeviceScreenButtons.test.js.map +0 -7
  11. package/lib/cjs/src/DeviceScreenImage.test.js +0 -2
  12. package/lib/cjs/src/DeviceScreenImage.test.js.map +0 -7
  13. package/lib/cjs/src/MockServerDevice.test.js +0 -2
  14. package/lib/cjs/src/MockServerDevice.test.js.map +0 -7
  15. package/lib/esm/src/DeviceOsInfo.test.js +0 -2
  16. package/lib/esm/src/DeviceOsInfo.test.js.map +0 -7
  17. package/lib/esm/src/DeviceScreen.test.js +0 -2
  18. package/lib/esm/src/DeviceScreen.test.js.map +0 -7
  19. package/lib/esm/src/DeviceScreenButtons.test.js +0 -2
  20. package/lib/esm/src/DeviceScreenButtons.test.js.map +0 -7
  21. package/lib/esm/src/DeviceScreenImage.test.js +0 -2
  22. package/lib/esm/src/DeviceScreenImage.test.js.map +0 -7
  23. package/lib/esm/src/MockServerDevice.test.js +0 -2
  24. package/lib/esm/src/MockServerDevice.test.js.map +0 -7
  25. package/lib/types/src/DeviceOsInfo.test.d.ts +0 -2
  26. package/lib/types/src/DeviceOsInfo.test.d.ts.map +0 -1
  27. package/lib/types/src/DeviceScreen.test.d.ts +0 -2
  28. package/lib/types/src/DeviceScreen.test.d.ts.map +0 -1
  29. package/lib/types/src/DeviceScreenButtons.test.d.ts +0 -2
  30. package/lib/types/src/DeviceScreenButtons.test.d.ts.map +0 -1
  31. package/lib/types/src/DeviceScreenImage.test.d.ts +0 -2
  32. package/lib/types/src/DeviceScreenImage.test.d.ts.map +0 -1
  33. package/lib/types/src/MockServerDevice.test.d.ts +0 -2
  34. package/lib/types/src/MockServerDevice.test.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "dependencies": {
3
- "@ledgerhq/device-mockserver-react-core": "0.0.0-develop-20261105000842",
4
- "@ledgerhq/device-mockserver-client": "0.0.0-develop-20261105000842"
3
+ "@ledgerhq/device-mockserver-client": "0.0.0-develop-20261107000805",
4
+ "@ledgerhq/device-mockserver-react-core": "0.0.0-develop-20261107000805"
5
5
  },
6
6
  "devDependencies": {
7
7
  "@ledgerhq/lumen-design-core": "0.1.34",
@@ -10,10 +10,10 @@
10
10
  "@types/react-dom": "18.3.1",
11
11
  "react": "18.3.1",
12
12
  "react-dom": "18.3.1",
13
- "@ledgerhq/device-management-kit": "0.0.0-develop-20261105000842",
14
- "@ledgerhq/eslint-config-dsdk": "0.0.2",
13
+ "@ledgerhq/device-management-kit": "0.0.0-develop-20261107000805",
15
14
  "@ledgerhq/ldmk-tool": "0.0.1",
16
15
  "@ledgerhq/prettier-config-dsdk": "0.0.2",
16
+ "@ledgerhq/eslint-config-dsdk": "0.0.2",
17
17
  "@ledgerhq/tsconfig-dsdk": "1.0.1",
18
18
  "@ledgerhq/vitest-config-dmk": "0.0.0"
19
19
  },
@@ -41,7 +41,7 @@
41
41
  "@ledgerhq/lumen-ui-react": "^0.1.66",
42
42
  "react": "18.3.1",
43
43
  "react-dom": "18.3.1",
44
- "@ledgerhq/device-management-kit": "0.0.0-develop-20261105000842"
44
+ "@ledgerhq/device-management-kit": "0.0.0-develop-20261107000805"
45
45
  },
46
46
  "private": false,
47
47
  "repository": {
@@ -49,7 +49,7 @@
49
49
  "url": "https://github.com/LedgerHQ/device-sdk-ts.git"
50
50
  },
51
51
  "types": "lib/index.d.ts",
52
- "version": "0.0.0-develop-20261105000842",
52
+ "version": "0.0.0-develop-20261107000805",
53
53
  "scripts": {
54
54
  "build": "pnpm ldmk-tool build --entryPoints index.ts,src/*.tsx,src/*.ts --tsconfig tsconfig.prod.json",
55
55
  "dev": "concurrently \"pnpm watch:builds\" \"pnpm watch:types\"",
@@ -1,2 +0,0 @@
1
- "use strict";var u=Object.create;var d=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var h=Object.getPrototypeOf,x=Object.prototype.hasOwnProperty;var b=(e,o,t,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let p of B(o))!x.call(e,p)&&p!==t&&d(e,p,{get:()=>o[p],enumerable:!(i=v(o,p))||i.enumerable});return e};var w=(e,o,t)=>(t=e!=null?u(h(e)):{},b(o||!e||!e.__esModule?d(t,"default",{value:e,enumerable:!0}):t,e));var n=w(require("react")),m=require("react-dom/client"),a=require("./deviceModels"),c=require("./DeviceOsInfo");Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});const r=e=>({id:"device-1",device_type:"stax",apps:e}),l=[{name:"BOLOS",version:"1.10.1"},{name:"Bitcoin",version:"2.5.0"},{name:"Ethereum",version:"1.22.3"}];describe("DeviceOsInfo",()=>{let e,o;const t=s=>e.querySelector(`[data-testid="${s}"]`),i=s=>(0,n.act)(()=>o.render(s)),p=async s=>(0,n.act)(async()=>{t(s).click(),await Promise.resolve()});beforeEach(()=>{vi.useFakeTimers(),e=document.createElement("div"),document.body.append(e),o=(0,m.createRoot)(e)}),afterEach(()=>{(0,n.act)(()=>o.unmount()),e.remove(),vi.useRealTimers()}),it("lists the installed apps, without the OS",()=>{i(n.default.createElement(c.DeviceOsInfo,{device:r(l),model:(0,a.findDeviceScreenModel)("stax")})),expect(t("button_open-app-Bitcoin")).not.toBeNull(),expect(t("button_open-app-Ethereum")).not.toBeNull(),expect(t("button_open-app-BOLOS")).toBeNull()}),it("says when no app is installed",()=>{i(n.default.createElement(c.DeviceOsInfo,{device:r([l[0]]),model:(0,a.findDeviceScreenModel)("nanoX")})),expect(t("list_device-apps")?.textContent).toBe("No apps installed")}),it("cannot open apps without an emulator",()=>{i(n.default.createElement(c.DeviceOsInfo,{device:r(l),model:(0,a.findDeviceScreenModel)("nanoS")})),expect(t("button_open-app-Bitcoin").disabled).toBe(!0)}),it("shows the app being opened",async()=>{const s=vi.fn(()=>new Promise(()=>{}));i(n.default.createElement(c.DeviceOsInfo,{device:r(l),model:(0,a.findDeviceScreenModel)("stax"),onOpenApp:s})),await p("button_open-app-Bitcoin"),expect(s).toHaveBeenCalledWith("Bitcoin"),expect(t("spinner_opening-app-screen")?.textContent).toContain("Opening Bitcoin")}),it("shows why an app could not be opened",async()=>{i(n.default.createElement(c.DeviceOsInfo,{device:r(l),model:(0,a.findDeviceScreenModel)("stax"),onOpenApp:()=>Promise.reject(new Error("Could not open (6d00)"))})),await p("button_open-app-Bitcoin"),expect(t("spinner_opening-app-screen")).toBeNull(),expect(e.textContent).toContain("Could not open (6d00)")}),it("gives up when an opened app never shows its screen",async()=>{i(n.default.createElement(c.DeviceOsInfo,{device:r(l),model:(0,a.findDeviceScreenModel)("stax"),onOpenApp:()=>Promise.resolve()})),await p("button_open-app-Ethereum"),(0,n.act)(()=>{vi.advanceTimersByTime(1e4)}),expect(e.textContent).toContain("Ethereum opened but its screen never showed up")}),it("falls back to the app's initial when its icon is missing",()=>{i(n.default.createElement(c.DeviceOsInfo,{device:r(l),model:(0,a.findDeviceScreenModel)("stax")})),(0,n.act)(()=>{t("button_open-app-Bitcoin").querySelector("img").dispatchEvent(new Event("error"))}),expect(t("button_open-app-Bitcoin")?.querySelector("img")).toBeNull(),expect(t("button_open-app-Bitcoin")?.textContent).toBe("BBitcoin")})});
2
- //# sourceMappingURL=DeviceOsInfo.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/DeviceOsInfo.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { type Device } from \"@ledgerhq/device-mockserver-client\";\n\nimport { findDeviceScreenModel } from \"./deviceModels\";\nimport { DeviceOsInfo } from \"./DeviceOsInfo\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\nconst aDevice = (apps: { name: string; version: string }[]) =>\n ({ id: \"device-1\", device_type: \"stax\", apps }) as unknown as Device;\n\nconst APPS = [\n { name: \"BOLOS\", version: \"1.10.1\" },\n { name: \"Bitcoin\", version: \"2.5.0\" },\n { name: \"Ethereum\", version: \"1.22.3\" },\n];\n\ndescribe(\"DeviceOsInfo\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n const query = (testId: string) =>\n container.querySelector<HTMLElement>(`[data-testid=\"${testId}\"]`);\n const render = (\n element: React.ReactElement<React.ComponentProps<typeof DeviceOsInfo>>,\n ) => act(() => root.render(element));\n const click = async (testId: string) =>\n act(async () => {\n query(testId)!.click();\n await Promise.resolve();\n });\n\n beforeEach(() => {\n vi.useFakeTimers();\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n it(\"lists the installed apps, without the OS\", () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n />,\n );\n\n expect(query(\"button_open-app-Bitcoin\")).not.toBeNull();\n expect(query(\"button_open-app-Ethereum\")).not.toBeNull();\n expect(query(\"button_open-app-BOLOS\")).toBeNull();\n });\n\n it(\"says when no app is installed\", () => {\n render(\n <DeviceOsInfo\n device={aDevice([APPS[0]!])}\n model={findDeviceScreenModel(\"nanoX\")}\n />,\n );\n\n expect(query(\"list_device-apps\")?.textContent).toBe(\"No apps installed\");\n });\n\n it(\"cannot open apps without an emulator\", () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"nanoS\")}\n />,\n );\n\n expect(\n (query(\"button_open-app-Bitcoin\") as HTMLButtonElement).disabled,\n ).toBe(true);\n });\n\n it(\"shows the app being opened\", async () => {\n const onOpenApp = vi.fn(() => new Promise<void>(() => {}));\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n onOpenApp={onOpenApp}\n />,\n );\n\n await click(\"button_open-app-Bitcoin\");\n\n expect(onOpenApp).toHaveBeenCalledWith(\"Bitcoin\");\n expect(query(\"spinner_opening-app-screen\")?.textContent).toContain(\n \"Opening Bitcoin\",\n );\n });\n\n it(\"shows why an app could not be opened\", async () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n onOpenApp={() => Promise.reject(new Error(\"Could not open (6d00)\"))}\n />,\n );\n\n await click(\"button_open-app-Bitcoin\");\n\n expect(query(\"spinner_opening-app-screen\")).toBeNull();\n expect(container.textContent).toContain(\"Could not open (6d00)\");\n });\n\n it(\"gives up when an opened app never shows its screen\", async () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n onOpenApp={() => Promise.resolve()}\n />,\n );\n\n await click(\"button_open-app-Ethereum\");\n act(() => {\n vi.advanceTimersByTime(10_000);\n });\n\n expect(container.textContent).toContain(\n \"Ethereum opened but its screen never showed up\",\n );\n });\n\n it(\"falls back to the app's initial when its icon is missing\", () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n />,\n );\n\n act(() => {\n query(\"button_open-app-Bitcoin\")!\n .querySelector(\"img\")!\n .dispatchEvent(new Event(\"error\"));\n });\n\n expect(query(\"button_open-app-Bitcoin\")?.querySelector(\"img\")).toBeNull();\n expect(query(\"button_open-app-Bitcoin\")?.textContent).toBe(\"BBitcoin\");\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["import_react", "import_client", "import_deviceModels", "import_DeviceOsInfo", "aDevice", "apps", "APPS", "container", "root", "query", "testId", "render", "element", "click", "React", "onOpenApp"]
7
- }
@@ -1,2 +0,0 @@
1
- "use strict";var f=Object.create;var h=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,b=Object.prototype.hasOwnProperty;var B=(n,l,i,o)=>{if(l&&typeof l=="object"||typeof l=="function")for(let t of x(l))!b.call(n,t)&&t!==i&&h(n,t,{get:()=>l[t],enumerable:!(o=g(l,t))||o.enumerable});return n};var C=(n,l,i)=>(i=n!=null?f(y(n)):{},B(l||!n||!n.__esModule?h(i,"default",{value:n,enumerable:!0}):i,n));var p=C(require("react")),w=require("react-dom/client"),u=require("./DeviceScreen");Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});const E={id:"device-1",device_type:"stax",apps:[{name:"Bitcoin",version:"2.5.0"}]},s=(n={})=>({screenshot:vi.fn(()=>Promise.resolve(null)),idle:vi.fn(()=>Promise.resolve({kind:"os-info",device:E})),pressButton:vi.fn(()=>Promise.resolve()),touch:vi.fn(()=>Promise.resolve()),openApp:vi.fn(()=>Promise.resolve()),...n});describe("DeviceScreen",()=>{let n,l;const i=e=>n.querySelector(`[data-testid="${e}"]`),o=e=>(0,p.act)(()=>l.render(p.default.createElement(u.DeviceScreen,{deviceType:"stax",...e}))),t=(e=0)=>(0,p.act)(()=>vi.advanceTimersByTimeAsync(e)),a=(e,r,c={})=>(0,p.act)(()=>{e.dispatchEvent(new MouseEvent(r,{bubbles:!0,button:0,...c}))});beforeEach(()=>{vi.useFakeTimers(),URL.createObjectURL=vi.fn(()=>"blob:frame"),URL.revokeObjectURL=vi.fn(),HTMLElement.prototype.setPointerCapture=vi.fn(),HTMLElement.prototype.releasePointerCapture=vi.fn(),n=document.createElement("div"),document.body.append(n),l=(0,w.createRoot)(n)}),afterEach(()=>{(0,p.act)(()=>l.unmount()),n.remove(),vi.useRealTimers()}),describe("inline",()=>{it("shows a placeholder until the screen answers",()=>{o({api:s({screenshot:()=>new Promise(()=>{})})}),expect(i("placeholder_device-screen-loading")).not.toBeNull()}),it("shows the live screen of a running app",async()=>{o({api:s({screenshot:()=>Promise.resolve(new Blob(["png"]))})}),await t(),expect(i("image_device-screen")?.getAttribute("src")).toBe("blob:frame")}),it("shows the installed apps while no app runs",async()=>{o({api:s()}),await t(),expect(i("button_open-app-Bitcoin")).not.toBeNull()}),it("says why a device without an emulator has no screen",async()=>{o({api:s(),deviceType:"nanoS"}),await t(),expect(i("button_open-app-Bitcoin")).not.toBeNull(),expect(n.textContent).toContain("Speculos has no emulator for the Nano S")}),it("says nothing about emulators for a device that has one",async()=>{o({api:s()}),await t(),expect(n.textContent).not.toContain("has no emulator")}),it("says there is no screen when the api has nothing to show instead",async()=>{o({api:s({idle:void 0})}),await t(),expect(n.textContent).toContain("No screen to capture")}),it("shows why the screen is unavailable",async()=>{o({api:s({screenshot:()=>Promise.reject(new Error("offline"))})}),await t(),expect(n.textContent).toContain("Screen unavailable"),expect(n.textContent).toContain("offline")}),it("keeps the last frame through a few failures while live",async()=>{const e=vi.fn().mockResolvedValueOnce(new Blob(["png"])).mockRejectedValue(new Error("app quitting")),r=()=>e.mock.calls.length-1;for(o({api:s({screenshot:e})}),await t();r()<3;)await t(500);for(expect(i("image_device-screen")).not.toBeNull();r()<4;)await t(500);expect(i("image_device-screen")).toBeNull(),expect(n.textContent).toContain("app quitting")}),it("drives a Nano with its buttons and refreshes after",async()=>{const e=s({screenshot:vi.fn(()=>Promise.resolve(new Blob(["png"])))});o({api:e,deviceType:"nanoX"}),await t(),a(i("button_device-screen-left"),"pointerdown"),a(i("button_device-screen-left"),"pointerup"),await t(),expect(e.pressButton).toHaveBeenCalledWith("left","press-and-release"),expect(e.screenshot).toHaveBeenCalledTimes(2)}),it("drives a touch device by its screen, without buttons",async()=>{o({api:s({screenshot:()=>Promise.resolve(new Blob(["png"]))})}),await t(),expect(i("image_device-screen")).not.toBeNull(),expect(i("button_device-screen-left")).toBeNull()})}),describe("floating",()=>{const e=()=>i("container_device-screen"),r=()=>e().firstElementChild;it("titles the window with the model and firmware",async()=>{o({api:s(),floating:!0,firmwareVersion:"1.10.1"}),await t(),expect(e().textContent).toContain("Stax - 1.10.1"),expect(e().style.width).toBe("224px")}),it("stops polling while collapsed",async()=>{const c=s();o({api:c,floating:!0,defaultCollapsed:!0}),await t(5e3),expect(c.screenshot).not.toHaveBeenCalled(),expect(i("button_open-app-Bitcoin")).toBeNull(),(0,p.act)(()=>i("button_toggle-device-screen").click()),await t(),expect(c.screenshot).toHaveBeenCalled(),expect(i("button_open-app-Bitcoin")).not.toBeNull()}),it("is dragged by its header",async()=>{o({api:s(),floating:!0}),await t(),a(r(),"pointerdown",{clientX:10,clientY:10}),a(r(),"pointermove",{clientX:110,clientY:60}),a(r(),"pointerup"),a(r(),"pointermove",{clientX:500,clientY:500}),expect(e().style.left).toBe("100px"),expect(e().style.top).toBe("50px")}),describe("when the viewport shrinks",()=>{const c={width:window.innerWidth,height:window.innerHeight},d=(v,m)=>(0,p.act)(()=>{Object.assign(window,{innerWidth:v,innerHeight:m}),window.dispatchEvent(new Event("resize"))});afterEach(()=>{Object.assign(window,{innerWidth:c.width,innerHeight:c.height})}),it("pulls a dragged window back on screen",async()=>{o({api:s(),floating:!0}),await t(),e().getBoundingClientRect=()=>({left:0,top:0,width:224,height:300}),a(r(),"pointerdown",{clientX:10,clientY:10}),a(r(),"pointermove",{clientX:610,clientY:410}),a(r(),"pointerup"),expect(e().style.left).toBe("600px"),d(500,500),expect(e().style.left).toBe("276px"),expect(e().style.top).toBe("200px")}),it("leaves a window that was never moved in its corner",async()=>{o({api:s(),floating:!0}),await t(),d(500,500),expect(e().style.left).toBe(""),expect(e().style.right).toBe("16px")})}),it("is not dragged from its button or with another mouse button",async()=>{o({api:s(),floating:!0}),await t(),a(i("button_toggle-device-screen"),"pointerdown"),a(r(),"pointerdown",{button:2}),a(r(),"pointermove",{clientX:110,clientY:60}),expect(e().style.left).toBe("")}),it("is resized from its edge, down to a minimum width",async()=>{o({api:s(),floating:!0}),await t(),e().getBoundingClientRect=()=>({left:100,top:80,width:224,height:300});const c=i("handle_resize-device-screen");a(c,"pointerdown",{clientX:324}),a(c,"pointermove",{clientX:424}),expect(e().style.width).toBe("324px"),expect(e().style.left).toBe("100px"),a(c,"pointermove",{clientX:0}),a(c,"pointerup"),a(c,"pointermove",{clientX:600}),expect(e().style.width).toBe("200px")})})});
2
- //# sourceMappingURL=DeviceScreen.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/DeviceScreen.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { type Device } from \"@ledgerhq/device-mockserver-client\";\nimport { type ScreenApi } from \"@ledgerhq/device-mockserver-react-core\";\n\nimport { DeviceScreen, type DeviceScreenProps } from \"./DeviceScreen\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\nconst DEVICE = {\n id: \"device-1\",\n device_type: \"stax\",\n apps: [{ name: \"Bitcoin\", version: \"2.5.0\" }],\n} as unknown as Device;\n\nconst anApi = (overrides: Partial<ScreenApi> = {}): ScreenApi => ({\n screenshot: vi.fn(() => Promise.resolve(null)),\n idle: vi.fn(() =>\n Promise.resolve({ kind: \"os-info\" as const, device: DEVICE }),\n ),\n pressButton: vi.fn(() => Promise.resolve()),\n touch: vi.fn(() => Promise.resolve()),\n openApp: vi.fn(() => Promise.resolve()),\n ...overrides,\n});\n\ndescribe(\"DeviceScreen\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n const query = (testId: string) =>\n container.querySelector<HTMLElement>(`[data-testid=\"${testId}\"]`);\n const render = (props: Partial<DeviceScreenProps> & { api: ScreenApi }) =>\n act(() => root.render(<DeviceScreen deviceType=\"stax\" {...props} />));\n const wait = (ms = 0) => act(() => vi.advanceTimersByTimeAsync(ms));\n const pointer = (target: Element, type: string, init: MouseEventInit = {}) =>\n act(() => {\n target.dispatchEvent(\n new MouseEvent(type, { bubbles: true, button: 0, ...init }),\n );\n });\n\n beforeEach(() => {\n vi.useFakeTimers();\n URL.createObjectURL = vi.fn(() => \"blob:frame\");\n URL.revokeObjectURL = vi.fn();\n HTMLElement.prototype.setPointerCapture = vi.fn();\n HTMLElement.prototype.releasePointerCapture = vi.fn();\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n describe(\"inline\", () => {\n it(\"shows a placeholder until the screen answers\", () => {\n render({ api: anApi({ screenshot: () => new Promise(() => {}) }) });\n\n expect(query(\"placeholder_device-screen-loading\")).not.toBeNull();\n });\n\n it(\"shows the live screen of a running app\", async () => {\n render({\n api: anApi({ screenshot: () => Promise.resolve(new Blob([\"png\"])) }),\n });\n await wait();\n\n expect(query(\"image_device-screen\")?.getAttribute(\"src\")).toBe(\n \"blob:frame\",\n );\n });\n\n it(\"shows the installed apps while no app runs\", async () => {\n render({ api: anApi() });\n await wait();\n\n expect(query(\"button_open-app-Bitcoin\")).not.toBeNull();\n });\n\n it(\"says why a device without an emulator has no screen\", async () => {\n render({ api: anApi(), deviceType: \"nanoS\" });\n await wait();\n\n expect(query(\"button_open-app-Bitcoin\")).not.toBeNull();\n expect(container.textContent).toContain(\n \"Speculos has no emulator for the Nano S\",\n );\n });\n\n it(\"says nothing about emulators for a device that has one\", async () => {\n render({ api: anApi() });\n await wait();\n\n expect(container.textContent).not.toContain(\"has no emulator\");\n });\n\n it(\"says there is no screen when the api has nothing to show instead\", async () => {\n render({ api: anApi({ idle: undefined }) });\n await wait();\n\n expect(container.textContent).toContain(\"No screen to capture\");\n });\n\n it(\"shows why the screen is unavailable\", async () => {\n render({\n api: anApi({ screenshot: () => Promise.reject(new Error(\"offline\")) }),\n });\n await wait();\n\n expect(container.textContent).toContain(\"Screen unavailable\");\n expect(container.textContent).toContain(\"offline\");\n });\n\n it(\"keeps the last frame through a few failures while live\", async () => {\n const screenshot = vi\n .fn<() => Promise<Blob | null>>()\n .mockResolvedValueOnce(new Blob([\"png\"]))\n .mockRejectedValue(new Error(\"app quitting\"));\n const failures = () => screenshot.mock.calls.length - 1;\n render({ api: anApi({ screenshot }) });\n await wait();\n\n while (failures() < 3) await wait(500);\n expect(query(\"image_device-screen\")).not.toBeNull();\n\n while (failures() < 4) await wait(500);\n expect(query(\"image_device-screen\")).toBeNull();\n expect(container.textContent).toContain(\"app quitting\");\n });\n\n it(\"drives a Nano with its buttons and refreshes after\", async () => {\n const api = anApi({\n screenshot: vi.fn(() => Promise.resolve(new Blob([\"png\"]))),\n });\n render({ api, deviceType: \"nanoX\" });\n await wait();\n\n pointer(query(\"button_device-screen-left\")!, \"pointerdown\");\n pointer(query(\"button_device-screen-left\")!, \"pointerup\");\n await wait();\n\n expect(api.pressButton).toHaveBeenCalledWith(\"left\", \"press-and-release\");\n expect(api.screenshot).toHaveBeenCalledTimes(2);\n });\n\n it(\"drives a touch device by its screen, without buttons\", async () => {\n render({\n api: anApi({ screenshot: () => Promise.resolve(new Blob([\"png\"])) }),\n });\n await wait();\n\n expect(query(\"image_device-screen\")).not.toBeNull();\n expect(query(\"button_device-screen-left\")).toBeNull();\n });\n });\n\n describe(\"floating\", () => {\n const windowElement = () => query(\"container_device-screen\")!;\n const header = () => windowElement().firstElementChild!;\n\n it(\"titles the window with the model and firmware\", async () => {\n render({ api: anApi(), floating: true, firmwareVersion: \"1.10.1\" });\n await wait();\n\n expect(windowElement().textContent).toContain(\"Stax - 1.10.1\");\n expect(windowElement().style.width).toBe(\"224px\");\n });\n\n it(\"stops polling while collapsed\", async () => {\n const api = anApi();\n render({ api, floating: true, defaultCollapsed: true });\n await wait(5000);\n\n expect(api.screenshot).not.toHaveBeenCalled();\n expect(query(\"button_open-app-Bitcoin\")).toBeNull();\n\n act(() => query(\"button_toggle-device-screen\")!.click());\n await wait();\n\n expect(api.screenshot).toHaveBeenCalled();\n expect(query(\"button_open-app-Bitcoin\")).not.toBeNull();\n });\n\n it(\"is dragged by its header\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n\n pointer(header(), \"pointerdown\", { clientX: 10, clientY: 10 });\n pointer(header(), \"pointermove\", { clientX: 110, clientY: 60 });\n pointer(header(), \"pointerup\");\n pointer(header(), \"pointermove\", { clientX: 500, clientY: 500 });\n\n expect(windowElement().style.left).toBe(\"100px\");\n expect(windowElement().style.top).toBe(\"50px\");\n });\n\n describe(\"when the viewport shrinks\", () => {\n const viewport = { width: window.innerWidth, height: window.innerHeight };\n const resizeViewport = (width: number, height: number) =>\n act(() => {\n Object.assign(window, { innerWidth: width, innerHeight: height });\n window.dispatchEvent(new Event(\"resize\"));\n });\n\n afterEach(() => {\n Object.assign(window, {\n innerWidth: viewport.width,\n innerHeight: viewport.height,\n });\n });\n\n it(\"pulls a dragged window back on screen\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n windowElement().getBoundingClientRect = () =>\n ({ left: 0, top: 0, width: 224, height: 300 }) as DOMRect;\n pointer(header(), \"pointerdown\", { clientX: 10, clientY: 10 });\n pointer(header(), \"pointermove\", { clientX: 610, clientY: 410 });\n pointer(header(), \"pointerup\");\n expect(windowElement().style.left).toBe(\"600px\");\n\n resizeViewport(500, 500);\n\n expect(windowElement().style.left).toBe(\"276px\");\n expect(windowElement().style.top).toBe(\"200px\");\n });\n\n it(\"leaves a window that was never moved in its corner\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n\n resizeViewport(500, 500);\n\n expect(windowElement().style.left).toBe(\"\");\n expect(windowElement().style.right).toBe(\"16px\");\n });\n });\n\n it(\"is not dragged from its button or with another mouse button\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n\n pointer(query(\"button_toggle-device-screen\")!, \"pointerdown\");\n pointer(header(), \"pointerdown\", { button: 2 });\n pointer(header(), \"pointermove\", { clientX: 110, clientY: 60 });\n\n expect(windowElement().style.left).toBe(\"\");\n });\n\n it(\"is resized from its edge, down to a minimum width\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n windowElement().getBoundingClientRect = () =>\n ({ left: 100, top: 80, width: 224, height: 300 }) as DOMRect;\n const handle = query(\"handle_resize-device-screen\")!;\n\n pointer(handle, \"pointerdown\", { clientX: 324 });\n pointer(handle, \"pointermove\", { clientX: 424 });\n expect(windowElement().style.width).toBe(\"324px\");\n expect(windowElement().style.left).toBe(\"100px\");\n\n pointer(handle, \"pointermove\", { clientX: 0 });\n pointer(handle, \"pointerup\");\n pointer(handle, \"pointermove\", { clientX: 600 });\n expect(windowElement().style.width).toBe(\"200px\");\n });\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["import_react", "import_client", "import_DeviceScreen", "DEVICE", "anApi", "overrides", "container", "root", "query", "testId", "render", "props", "React", "wait", "ms", "pointer", "target", "type", "init", "screenshot", "failures", "api", "windowElement", "header", "viewport", "resizeViewport", "width", "height", "handle"]
7
- }
@@ -1,2 +0,0 @@
1
- "use strict";var h=Object.create;var p=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var b=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var f=(t,r,e,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of v(r))!E.call(t,o)&&o!==e&&p(t,o,{get:()=>r[o],enumerable:!(n=m(r,o))||n.enumerable});return t};var g=(t,r,e)=>(e=t!=null?h(b(t)):{},f(r||!t||!t.__esModule?p(e,"default",{value:t,enumerable:!0}):e,t));var s=g(require("react")),c=require("react-dom/client"),u=require("./DeviceScreenButtons");Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});describe("DeviceScreenButtons",()=>{let t,r;const e=vi.fn(),n=i=>t.querySelector(`[data-testid="button_device-screen-${i}"]`),o=(i,l,d={})=>(0,s.act)(()=>{i.dispatchEvent(new MouseEvent(l,{bubbles:!0,button:0,...d}))}),a=(i,l,d)=>(0,s.act)(()=>{i.dispatchEvent(new KeyboardEvent(l,{bubbles:!0,key:d}))});beforeEach(()=>{vi.useFakeTimers(),e.mockReset(),HTMLElement.prototype.setPointerCapture=vi.fn(),t=document.createElement("div"),document.body.append(t),r=(0,c.createRoot)(t),(0,s.act)(()=>r.render(s.default.createElement(u.DeviceScreenButtons,{onPress:e})))}),afterEach(()=>{(0,s.act)(()=>r.unmount()),t.remove(),vi.useRealTimers()}),it("sends a quick click as one press-and-release",()=>{o(n("left"),"pointerdown"),o(n("left"),"pointerup"),expect(e).toHaveBeenCalledOnce(),expect(e).toHaveBeenCalledWith("left","press-and-release")}),it("sends a hold as a press then a release",()=>{o(n("both"),"pointerdown"),(0,s.act)(()=>{vi.advanceTimersByTime(200)}),o(n("both"),"pointerup"),expect(e.mock.calls).toEqual([["both","press"],["both","release"]])}),it("ignores buttons other than the main one",()=>{o(n("right"),"pointerdown",{button:2}),o(n("right"),"pointerup",{button:2}),expect(e).not.toHaveBeenCalled()}),it("handles one button at a time",()=>{o(n("left"),"pointerdown"),o(n("right"),"pointerdown"),o(n("left"),"pointerup"),expect(e).toHaveBeenCalledWith("left","press-and-release"),expect(e).toHaveBeenCalledOnce()}),it("drives the buttons from the keyboard",()=>{a(n("right"),"keydown","Enter"),a(n("right"),"keyup","Enter"),a(n("right"),"keydown","a"),expect(e).toHaveBeenCalledOnce(),expect(e).toHaveBeenCalledWith("right","press-and-release")}),it("releases a held button when unmounted",()=>{o(n("left"),"pointerdown"),(0,s.act)(()=>{vi.advanceTimersByTime(200)}),(0,s.act)(()=>r.render(s.default.createElement(s.default.Fragment,null))),expect(e).toHaveBeenLastCalledWith("left","release")})});
2
- //# sourceMappingURL=DeviceScreenButtons.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/DeviceScreenButtons.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\n\nimport { DeviceScreenButtons } from \"./DeviceScreenButtons\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\ndescribe(\"DeviceScreenButtons\", () => {\n let container: HTMLDivElement;\n let root: Root;\n const onPress = vi.fn();\n\n const button = (name: string) =>\n container.querySelector<HTMLButtonElement>(\n `[data-testid=\"button_device-screen-${name}\"]`,\n )!;\n const pointer = (target: Element, type: string, init: MouseEventInit = {}) =>\n act(() => {\n target.dispatchEvent(\n new MouseEvent(type, { bubbles: true, button: 0, ...init }),\n );\n });\n const key = (target: Element, type: string, value: string) =>\n act(() => {\n target.dispatchEvent(\n new KeyboardEvent(type, { bubbles: true, key: value }),\n );\n });\n\n beforeEach(() => {\n vi.useFakeTimers();\n onPress.mockReset();\n HTMLElement.prototype.setPointerCapture = vi.fn();\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n act(() => root.render(<DeviceScreenButtons onPress={onPress} />));\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n it(\"sends a quick click as one press-and-release\", () => {\n pointer(button(\"left\"), \"pointerdown\");\n pointer(button(\"left\"), \"pointerup\");\n\n expect(onPress).toHaveBeenCalledOnce();\n expect(onPress).toHaveBeenCalledWith(\"left\", \"press-and-release\");\n });\n\n it(\"sends a hold as a press then a release\", () => {\n pointer(button(\"both\"), \"pointerdown\");\n act(() => {\n vi.advanceTimersByTime(200);\n });\n pointer(button(\"both\"), \"pointerup\");\n\n expect(onPress.mock.calls).toEqual([\n [\"both\", \"press\"],\n [\"both\", \"release\"],\n ]);\n });\n\n it(\"ignores buttons other than the main one\", () => {\n pointer(button(\"right\"), \"pointerdown\", { button: 2 });\n pointer(button(\"right\"), \"pointerup\", { button: 2 });\n\n expect(onPress).not.toHaveBeenCalled();\n });\n\n it(\"handles one button at a time\", () => {\n pointer(button(\"left\"), \"pointerdown\");\n pointer(button(\"right\"), \"pointerdown\");\n pointer(button(\"left\"), \"pointerup\");\n\n expect(onPress).toHaveBeenCalledWith(\"left\", \"press-and-release\");\n expect(onPress).toHaveBeenCalledOnce();\n });\n\n it(\"drives the buttons from the keyboard\", () => {\n key(button(\"right\"), \"keydown\", \"Enter\");\n key(button(\"right\"), \"keyup\", \"Enter\");\n key(button(\"right\"), \"keydown\", \"a\");\n\n expect(onPress).toHaveBeenCalledOnce();\n expect(onPress).toHaveBeenCalledWith(\"right\", \"press-and-release\");\n });\n\n it(\"releases a held button when unmounted\", () => {\n pointer(button(\"left\"), \"pointerdown\");\n act(() => {\n vi.advanceTimersByTime(200);\n });\n act(() => root.render(<></>));\n\n expect(onPress).toHaveBeenLastCalledWith(\"left\", \"release\");\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["import_react", "import_client", "import_DeviceScreenButtons", "container", "root", "onPress", "button", "name", "pointer", "target", "type", "init", "key", "value", "React"]
7
- }
@@ -1,2 +0,0 @@
1
- "use strict";var h=Object.create;var d=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var T=Object.getPrototypeOf,b=Object.prototype.hasOwnProperty;var g=(t,n,e,a)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of E(n))!b.call(t,o)&&o!==e&&d(t,o,{get:()=>n[o],enumerable:!(a=v(n,o))||a.enumerable});return t};var f=(t,n,e)=>(e=t!=null?h(T(t)):{},g(n||!t||!t.__esModule?d(e,"default",{value:t,enumerable:!0}):e,t));var i=f(require("react")),p=require("react-dom/client"),s=require("@ledgerhq/device-mockserver-react-core"),u=require("./DeviceScreenImage");Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});describe("DeviceScreenImage",()=>{let t,n;const e=vi.fn(),a=()=>t.querySelector('[data-testid="image_device-screen"]'),o=l=>(0,i.act)(()=>n.render(i.default.createElement(u.DeviceScreenImage,{src:"blob:1",onTouch:l}))),r=(l,m={})=>(0,i.act)(()=>{a().dispatchEvent(new MouseEvent(l,{bubbles:!0,button:0,...m}))}),c=()=>{Object.defineProperty(a(),"naturalWidth",{value:400}),Object.defineProperty(a(),"naturalHeight",{value:600}),a().getBoundingClientRect=()=>({left:0,top:0,width:200,height:300})};beforeEach(()=>{vi.useFakeTimers(),e.mockReset(),HTMLElement.prototype.setPointerCapture=vi.fn(),HTMLElement.prototype.releasePointerCapture=vi.fn(),t=document.createElement("div"),document.body.append(t),n=(0,p.createRoot)(t)}),afterEach(()=>{(0,i.act)(()=>n.unmount()),t.remove(),vi.useRealTimers()}),it("maps a tap to device pixels",()=>{o(e),c(),r("pointerdown",{clientX:50,clientY:150}),r("pointerup",{clientX:190,clientY:10}),expect(e).toHaveBeenCalledExactlyOnceWith(100,300,"press-and-release")}),it("releases a hold where it went down",()=>{o(e),c(),r("pointerdown",{clientX:50,clientY:150}),(0,i.act)(()=>{vi.advanceTimersByTime(s.HOLD_THRESHOLD_MS)}),r("pointerup",{clientX:190,clientY:10}),expect(e.mock.calls).toEqual([[100,300,"press"],[100,300,"release"]])}),it("clamps a touch on the far edge to the last pixel",()=>{o(e),c(),r("pointerdown",{clientX:200,clientY:300}),r("pointerup"),expect(e).toHaveBeenCalledWith(399,599,"press-and-release")}),it("ignores touches before the image has a size",()=>{o(e),r("pointerdown",{clientX:10,clientY:10}),r("pointerup"),expect(e).not.toHaveBeenCalled()}),it("ignores touches on a button-driven device",()=>{o(),c(),r("pointerdown",{clientX:10,clientY:10}),expect(e).not.toHaveBeenCalled()}),it("releases a held touch when unmounted",()=>{o(e),c(),r("pointerdown",{clientX:50,clientY:150}),(0,i.act)(()=>{vi.advanceTimersByTime(s.HOLD_THRESHOLD_MS)}),(0,i.act)(()=>n.render(i.default.createElement(i.default.Fragment,null))),expect(e).toHaveBeenLastCalledWith(100,300,"release")}),it("says so when the screenshot cannot be decoded",()=>{o(e),(0,i.act)(()=>{a().dispatchEvent(new Event("error"))}),expect(t.querySelector('[data-testid="text_device-screen-undecodable"]')).not.toBeNull()})});
2
- //# sourceMappingURL=DeviceScreenImage.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/DeviceScreenImage.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { HOLD_THRESHOLD_MS } from \"@ledgerhq/device-mockserver-react-core\";\n\nimport { DeviceScreenImage } from \"./DeviceScreenImage\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\ndescribe(\"DeviceScreenImage\", () => {\n let container: HTMLDivElement;\n let root: Root;\n const onTouch = vi.fn();\n\n const image = () =>\n container.querySelector<HTMLImageElement>(\n '[data-testid=\"image_device-screen\"]',\n )!;\n const render = (touch?: typeof onTouch) =>\n act(() => root.render(<DeviceScreenImage src=\"blob:1\" onTouch={touch} />));\n const pointer = (type: string, init: MouseEventInit = {}) =>\n act(() => {\n image().dispatchEvent(\n new MouseEvent(type, { bubbles: true, button: 0, ...init }),\n );\n });\n /** A 400x600 screen drawn at 200x300 from the page's top left corner. */\n const sizeImage = () => {\n Object.defineProperty(image(), \"naturalWidth\", { value: 400 });\n Object.defineProperty(image(), \"naturalHeight\", { value: 600 });\n image().getBoundingClientRect = () =>\n ({ left: 0, top: 0, width: 200, height: 300 }) as DOMRect;\n };\n\n beforeEach(() => {\n vi.useFakeTimers();\n onTouch.mockReset();\n HTMLElement.prototype.setPointerCapture = vi.fn();\n HTMLElement.prototype.releasePointerCapture = vi.fn();\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n it(\"maps a tap to device pixels\", () => {\n render(onTouch);\n sizeImage();\n\n pointer(\"pointerdown\", { clientX: 50, clientY: 150 });\n pointer(\"pointerup\", { clientX: 190, clientY: 10 });\n\n expect(onTouch).toHaveBeenCalledExactlyOnceWith(\n 100,\n 300,\n \"press-and-release\",\n );\n });\n\n it(\"releases a hold where it went down\", () => {\n render(onTouch);\n sizeImage();\n\n pointer(\"pointerdown\", { clientX: 50, clientY: 150 });\n act(() => {\n vi.advanceTimersByTime(HOLD_THRESHOLD_MS);\n });\n pointer(\"pointerup\", { clientX: 190, clientY: 10 });\n\n expect(onTouch.mock.calls).toEqual([\n [100, 300, \"press\"],\n [100, 300, \"release\"],\n ]);\n });\n\n it(\"clamps a touch on the far edge to the last pixel\", () => {\n render(onTouch);\n sizeImage();\n\n pointer(\"pointerdown\", { clientX: 200, clientY: 300 });\n pointer(\"pointerup\");\n\n expect(onTouch).toHaveBeenCalledWith(399, 599, \"press-and-release\");\n });\n\n it(\"ignores touches before the image has a size\", () => {\n render(onTouch);\n\n pointer(\"pointerdown\", { clientX: 10, clientY: 10 });\n pointer(\"pointerup\");\n\n expect(onTouch).not.toHaveBeenCalled();\n });\n\n it(\"ignores touches on a button-driven device\", () => {\n render();\n sizeImage();\n\n pointer(\"pointerdown\", { clientX: 10, clientY: 10 });\n\n expect(onTouch).not.toHaveBeenCalled();\n });\n\n it(\"releases a held touch when unmounted\", () => {\n render(onTouch);\n sizeImage();\n pointer(\"pointerdown\", { clientX: 50, clientY: 150 });\n act(() => {\n vi.advanceTimersByTime(HOLD_THRESHOLD_MS);\n });\n\n act(() => root.render(<></>));\n\n expect(onTouch).toHaveBeenLastCalledWith(100, 300, \"release\");\n });\n\n it(\"says so when the screenshot cannot be decoded\", () => {\n render(onTouch);\n\n act(() => {\n image().dispatchEvent(new Event(\"error\"));\n });\n\n expect(\n container.querySelector('[data-testid=\"text_device-screen-undecodable\"]'),\n ).not.toBeNull();\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["import_react", "import_client", "import_device_mockserver_react_core", "import_DeviceScreenImage", "container", "root", "onTouch", "image", "render", "touch", "React", "pointer", "type", "init", "sizeImage"]
7
- }
@@ -1,2 +0,0 @@
1
- "use strict";var l=Object.create;var s=Object.defineProperty;var d=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var u=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let c of v(t))!h.call(e,c)&&c!==o&&s(e,c,{get:()=>t[c],enumerable:!(i=d(t,c))||i.enumerable});return e};var p=(e,t,o)=>(o=e!=null?l(k(e)):{},u(t||!e||!e.__esModule?s(o,"default",{value:e,enumerable:!0}):o,e));var n=p(require("react")),a=require("react-dom/client"),r=require("@ledgerhq/device-mockserver-client"),m=require("./MockServerDevice");Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});vi.mock("@ledgerhq/device-mockserver-client",()=>({MockClient:vi.fn()}));describe("MockServerDevice",()=>{let e,t;const o=vi.fn();beforeEach(()=>{vi.useFakeTimers(),o.mockReset(),vi.mocked(r.MockClient).mockImplementation(()=>({getDevice:o,getScreenshot:()=>new Promise(()=>{})})),e=document.createElement("div"),document.body.append(e),t=(0,a.createRoot)(e)}),afterEach(()=>{(0,n.act)(()=>t.unmount()),e.remove(),vi.useRealTimers()});const i=()=>(0,n.act)(()=>t.render(n.default.createElement(m.MockServerDevice,{url:"http://mock",token:"session-token",deviceId:"device-1",floating:!0})));it("renders nothing until the device's model is known",()=>{o.mockReturnValue(new Promise(()=>{})),i(),expect(e.childElementCount).toBe(0)}),it("shows the device's screen in its session",async()=>{o.mockResolvedValue({id:"device-1",device_type:"flex",firmware_version:"1.6.1"}),i(),await(0,n.act)(()=>vi.advanceTimersByTimeAsync(0)),expect(r.MockClient).toHaveBeenCalledWith("http://mock",{token:"session-token"}),expect(o).toHaveBeenCalledWith("device-1"),expect(e.textContent).toContain("Flex - 1.6.1")}),it("still shows the screen when the device cannot be read",async()=>{o.mockRejectedValue(new Error("offline")),i(),await(0,n.act)(()=>vi.advanceTimersByTimeAsync(0)),expect(e.querySelector('[data-testid="container_device-screen"]')).not.toBeNull()})});
2
- //# sourceMappingURL=MockServerDevice.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/MockServerDevice.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { MockClient } from \"@ledgerhq/device-mockserver-client\";\n\nimport { MockServerDevice } from \"./MockServerDevice\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\nvi.mock(\"@ledgerhq/device-mockserver-client\", () => ({\n MockClient: vi.fn(),\n}));\n\ndescribe(\"MockServerDevice\", () => {\n let container: HTMLDivElement;\n let root: Root;\n const getDevice = vi.fn();\n\n beforeEach(() => {\n vi.useFakeTimers();\n getDevice.mockReset();\n vi.mocked(MockClient).mockImplementation(\n () =>\n ({\n getDevice,\n getScreenshot: () => new Promise(() => {}),\n }) as unknown as MockClient,\n );\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n const render = () =>\n act(() =>\n root.render(\n <MockServerDevice\n url=\"http://mock\"\n token=\"session-token\"\n deviceId=\"device-1\"\n floating\n />,\n ),\n );\n\n it(\"renders nothing until the device's model is known\", () => {\n getDevice.mockReturnValue(new Promise(() => {}));\n\n render();\n\n expect(container.childElementCount).toBe(0);\n });\n\n it(\"shows the device's screen in its session\", async () => {\n getDevice.mockResolvedValue({\n id: \"device-1\",\n device_type: \"flex\",\n firmware_version: \"1.6.1\",\n });\n\n render();\n await act(() => vi.advanceTimersByTimeAsync(0));\n\n expect(MockClient).toHaveBeenCalledWith(\"http://mock\", {\n token: \"session-token\",\n });\n expect(getDevice).toHaveBeenCalledWith(\"device-1\");\n expect(container.textContent).toContain(\"Flex - 1.6.1\");\n });\n\n it(\"still shows the screen when the device cannot be read\", async () => {\n getDevice.mockRejectedValue(new Error(\"offline\"));\n\n render();\n await act(() => vi.advanceTimersByTimeAsync(0));\n\n expect(\n container.querySelector('[data-testid=\"container_device-screen\"]'),\n ).not.toBeNull();\n });\n});\n"],
5
- "mappings": "wdAAA,IAAAA,EAA2B,oBAC3BC,EAAsC,4BACtCC,EAA2B,8CAE3BC,EAAiC,8BAEjC,OAAO,OAAO,WAAY,CAAE,yBAA0B,EAAK,CAAC,EAE5D,GAAG,KAAK,qCAAsC,KAAO,CACnD,WAAY,GAAG,GAAG,CACpB,EAAE,EAEF,SAAS,mBAAoB,IAAM,CACjC,IAAIC,EACAC,EACJ,MAAMC,EAAY,GAAG,GAAG,EAExB,WAAW,IAAM,CACf,GAAG,cAAc,EACjBA,EAAU,UAAU,EACpB,GAAG,OAAO,YAAU,EAAE,mBACpB,KACG,CACC,UAAAA,EACA,cAAe,IAAM,IAAI,QAAQ,IAAM,CAAC,CAAC,CAC3C,EACJ,EACAF,EAAY,SAAS,cAAc,KAAK,EACxC,SAAS,KAAK,OAAOA,CAAS,EAC9BC,KAAO,cAAWD,CAAS,CAC7B,CAAC,EAED,UAAU,IAAM,IACd,OAAI,IAAMC,EAAK,QAAQ,CAAC,EACxBD,EAAU,OAAO,EACjB,GAAG,cAAc,CACnB,CAAC,EAED,MAAMG,EAAS,OACb,OAAI,IACFF,EAAK,OACH,EAAAG,QAAA,cAAC,oBACC,IAAI,cACJ,MAAM,gBACN,SAAS,WACT,SAAQ,GACV,CACF,CACF,EAEF,GAAG,oDAAqD,IAAM,CAC5DF,EAAU,gBAAgB,IAAI,QAAQ,IAAM,CAAC,CAAC,CAAC,EAE/CC,EAAO,EAEP,OAAOH,EAAU,iBAAiB,EAAE,KAAK,CAAC,CAC5C,CAAC,EAED,GAAG,2CAA4C,SAAY,CACzDE,EAAU,kBAAkB,CAC1B,GAAI,WACJ,YAAa,OACb,iBAAkB,OACpB,CAAC,EAEDC,EAAO,EACP,QAAM,OAAI,IAAM,GAAG,yBAAyB,CAAC,CAAC,EAE9C,OAAO,YAAU,EAAE,qBAAqB,cAAe,CACrD,MAAO,eACT,CAAC,EACD,OAAOD,CAAS,EAAE,qBAAqB,UAAU,EACjD,OAAOF,EAAU,WAAW,EAAE,UAAU,cAAc,CACxD,CAAC,EAED,GAAG,wDAAyD,SAAY,CACtEE,EAAU,kBAAkB,IAAI,MAAM,SAAS,CAAC,EAEhDC,EAAO,EACP,QAAM,OAAI,IAAM,GAAG,yBAAyB,CAAC,CAAC,EAE9C,OACEH,EAAU,cAAc,yCAAyC,CACnE,EAAE,IAAI,SAAS,CACjB,CAAC,CACH,CAAC",
6
- "names": ["import_react", "import_client", "import_device_mockserver_client", "import_MockServerDevice", "container", "root", "getDevice", "render", "React"]
7
- }
@@ -1,2 +0,0 @@
1
- import i,{act as r}from"react";import{createRoot as m}from"react-dom/client";import{findDeviceScreenModel as p}from"./deviceModels";import{DeviceOsInfo as s}from"./DeviceOsInfo";Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});const a=t=>({id:"device-1",device_type:"stax",apps:t}),c=[{name:"BOLOS",version:"1.10.1"},{name:"Bitcoin",version:"2.5.0"},{name:"Ethereum",version:"1.22.3"}];describe("DeviceOsInfo",()=>{let t,l;const e=n=>t.querySelector(`[data-testid="${n}"]`),o=n=>r(()=>l.render(n)),d=async n=>r(async()=>{e(n).click(),await Promise.resolve()});beforeEach(()=>{vi.useFakeTimers(),t=document.createElement("div"),document.body.append(t),l=m(t)}),afterEach(()=>{r(()=>l.unmount()),t.remove(),vi.useRealTimers()}),it("lists the installed apps, without the OS",()=>{o(i.createElement(s,{device:a(c),model:p("stax")})),expect(e("button_open-app-Bitcoin")).not.toBeNull(),expect(e("button_open-app-Ethereum")).not.toBeNull(),expect(e("button_open-app-BOLOS")).toBeNull()}),it("says when no app is installed",()=>{o(i.createElement(s,{device:a([c[0]]),model:p("nanoX")})),expect(e("list_device-apps")?.textContent).toBe("No apps installed")}),it("cannot open apps without an emulator",()=>{o(i.createElement(s,{device:a(c),model:p("nanoS")})),expect(e("button_open-app-Bitcoin").disabled).toBe(!0)}),it("shows the app being opened",async()=>{const n=vi.fn(()=>new Promise(()=>{}));o(i.createElement(s,{device:a(c),model:p("stax"),onOpenApp:n})),await d("button_open-app-Bitcoin"),expect(n).toHaveBeenCalledWith("Bitcoin"),expect(e("spinner_opening-app-screen")?.textContent).toContain("Opening Bitcoin")}),it("shows why an app could not be opened",async()=>{o(i.createElement(s,{device:a(c),model:p("stax"),onOpenApp:()=>Promise.reject(new Error("Could not open (6d00)"))})),await d("button_open-app-Bitcoin"),expect(e("spinner_opening-app-screen")).toBeNull(),expect(t.textContent).toContain("Could not open (6d00)")}),it("gives up when an opened app never shows its screen",async()=>{o(i.createElement(s,{device:a(c),model:p("stax"),onOpenApp:()=>Promise.resolve()})),await d("button_open-app-Ethereum"),r(()=>{vi.advanceTimersByTime(1e4)}),expect(t.textContent).toContain("Ethereum opened but its screen never showed up")}),it("falls back to the app's initial when its icon is missing",()=>{o(i.createElement(s,{device:a(c),model:p("stax")})),r(()=>{e("button_open-app-Bitcoin").querySelector("img").dispatchEvent(new Event("error"))}),expect(e("button_open-app-Bitcoin")?.querySelector("img")).toBeNull(),expect(e("button_open-app-Bitcoin")?.textContent).toBe("BBitcoin")})});
2
- //# sourceMappingURL=DeviceOsInfo.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/DeviceOsInfo.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { type Device } from \"@ledgerhq/device-mockserver-client\";\n\nimport { findDeviceScreenModel } from \"./deviceModels\";\nimport { DeviceOsInfo } from \"./DeviceOsInfo\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\nconst aDevice = (apps: { name: string; version: string }[]) =>\n ({ id: \"device-1\", device_type: \"stax\", apps }) as unknown as Device;\n\nconst APPS = [\n { name: \"BOLOS\", version: \"1.10.1\" },\n { name: \"Bitcoin\", version: \"2.5.0\" },\n { name: \"Ethereum\", version: \"1.22.3\" },\n];\n\ndescribe(\"DeviceOsInfo\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n const query = (testId: string) =>\n container.querySelector<HTMLElement>(`[data-testid=\"${testId}\"]`);\n const render = (\n element: React.ReactElement<React.ComponentProps<typeof DeviceOsInfo>>,\n ) => act(() => root.render(element));\n const click = async (testId: string) =>\n act(async () => {\n query(testId)!.click();\n await Promise.resolve();\n });\n\n beforeEach(() => {\n vi.useFakeTimers();\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n it(\"lists the installed apps, without the OS\", () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n />,\n );\n\n expect(query(\"button_open-app-Bitcoin\")).not.toBeNull();\n expect(query(\"button_open-app-Ethereum\")).not.toBeNull();\n expect(query(\"button_open-app-BOLOS\")).toBeNull();\n });\n\n it(\"says when no app is installed\", () => {\n render(\n <DeviceOsInfo\n device={aDevice([APPS[0]!])}\n model={findDeviceScreenModel(\"nanoX\")}\n />,\n );\n\n expect(query(\"list_device-apps\")?.textContent).toBe(\"No apps installed\");\n });\n\n it(\"cannot open apps without an emulator\", () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"nanoS\")}\n />,\n );\n\n expect(\n (query(\"button_open-app-Bitcoin\") as HTMLButtonElement).disabled,\n ).toBe(true);\n });\n\n it(\"shows the app being opened\", async () => {\n const onOpenApp = vi.fn(() => new Promise<void>(() => {}));\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n onOpenApp={onOpenApp}\n />,\n );\n\n await click(\"button_open-app-Bitcoin\");\n\n expect(onOpenApp).toHaveBeenCalledWith(\"Bitcoin\");\n expect(query(\"spinner_opening-app-screen\")?.textContent).toContain(\n \"Opening Bitcoin\",\n );\n });\n\n it(\"shows why an app could not be opened\", async () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n onOpenApp={() => Promise.reject(new Error(\"Could not open (6d00)\"))}\n />,\n );\n\n await click(\"button_open-app-Bitcoin\");\n\n expect(query(\"spinner_opening-app-screen\")).toBeNull();\n expect(container.textContent).toContain(\"Could not open (6d00)\");\n });\n\n it(\"gives up when an opened app never shows its screen\", async () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n onOpenApp={() => Promise.resolve()}\n />,\n );\n\n await click(\"button_open-app-Ethereum\");\n act(() => {\n vi.advanceTimersByTime(10_000);\n });\n\n expect(container.textContent).toContain(\n \"Ethereum opened but its screen never showed up\",\n );\n });\n\n it(\"falls back to the app's initial when its icon is missing\", () => {\n render(\n <DeviceOsInfo\n device={aDevice(APPS)}\n model={findDeviceScreenModel(\"stax\")}\n />,\n );\n\n act(() => {\n query(\"button_open-app-Bitcoin\")!\n .querySelector(\"img\")!\n .dispatchEvent(new Event(\"error\"));\n });\n\n expect(query(\"button_open-app-Bitcoin\")?.querySelector(\"img\")).toBeNull();\n expect(query(\"button_open-app-Bitcoin\")?.textContent).toBe(\"BBitcoin\");\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["React", "act", "createRoot", "findDeviceScreenModel", "DeviceOsInfo", "aDevice", "apps", "APPS", "container", "root", "query", "testId", "render", "element", "click", "onOpenApp"]
7
- }
@@ -1,2 +0,0 @@
1
- import u,{act as l}from"react";import{createRoot as v}from"react-dom/client";import{DeviceScreen as m}from"./DeviceScreen";Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});const f={id:"device-1",device_type:"stax",apps:[{name:"Bitcoin",version:"2.5.0"}]},o=(c={})=>({screenshot:vi.fn(()=>Promise.resolve(null)),idle:vi.fn(()=>Promise.resolve({kind:"os-info",device:f})),pressButton:vi.fn(()=>Promise.resolve()),touch:vi.fn(()=>Promise.resolve()),openApp:vi.fn(()=>Promise.resolve()),...c});describe("DeviceScreen",()=>{let c,p;const a=e=>c.querySelector(`[data-testid="${e}"]`),n=e=>l(()=>p.render(u.createElement(m,{deviceType:"stax",...e}))),t=(e=0)=>l(()=>vi.advanceTimersByTimeAsync(e)),i=(e,s,r={})=>l(()=>{e.dispatchEvent(new MouseEvent(s,{bubbles:!0,button:0,...r}))});beforeEach(()=>{vi.useFakeTimers(),URL.createObjectURL=vi.fn(()=>"blob:frame"),URL.revokeObjectURL=vi.fn(),HTMLElement.prototype.setPointerCapture=vi.fn(),HTMLElement.prototype.releasePointerCapture=vi.fn(),c=document.createElement("div"),document.body.append(c),p=v(c)}),afterEach(()=>{l(()=>p.unmount()),c.remove(),vi.useRealTimers()}),describe("inline",()=>{it("shows a placeholder until the screen answers",()=>{n({api:o({screenshot:()=>new Promise(()=>{})})}),expect(a("placeholder_device-screen-loading")).not.toBeNull()}),it("shows the live screen of a running app",async()=>{n({api:o({screenshot:()=>Promise.resolve(new Blob(["png"]))})}),await t(),expect(a("image_device-screen")?.getAttribute("src")).toBe("blob:frame")}),it("shows the installed apps while no app runs",async()=>{n({api:o()}),await t(),expect(a("button_open-app-Bitcoin")).not.toBeNull()}),it("says why a device without an emulator has no screen",async()=>{n({api:o(),deviceType:"nanoS"}),await t(),expect(a("button_open-app-Bitcoin")).not.toBeNull(),expect(c.textContent).toContain("Speculos has no emulator for the Nano S")}),it("says nothing about emulators for a device that has one",async()=>{n({api:o()}),await t(),expect(c.textContent).not.toContain("has no emulator")}),it("says there is no screen when the api has nothing to show instead",async()=>{n({api:o({idle:void 0})}),await t(),expect(c.textContent).toContain("No screen to capture")}),it("shows why the screen is unavailable",async()=>{n({api:o({screenshot:()=>Promise.reject(new Error("offline"))})}),await t(),expect(c.textContent).toContain("Screen unavailable"),expect(c.textContent).toContain("offline")}),it("keeps the last frame through a few failures while live",async()=>{const e=vi.fn().mockResolvedValueOnce(new Blob(["png"])).mockRejectedValue(new Error("app quitting")),s=()=>e.mock.calls.length-1;for(n({api:o({screenshot:e})}),await t();s()<3;)await t(500);for(expect(a("image_device-screen")).not.toBeNull();s()<4;)await t(500);expect(a("image_device-screen")).toBeNull(),expect(c.textContent).toContain("app quitting")}),it("drives a Nano with its buttons and refreshes after",async()=>{const e=o({screenshot:vi.fn(()=>Promise.resolve(new Blob(["png"])))});n({api:e,deviceType:"nanoX"}),await t(),i(a("button_device-screen-left"),"pointerdown"),i(a("button_device-screen-left"),"pointerup"),await t(),expect(e.pressButton).toHaveBeenCalledWith("left","press-and-release"),expect(e.screenshot).toHaveBeenCalledTimes(2)}),it("drives a touch device by its screen, without buttons",async()=>{n({api:o({screenshot:()=>Promise.resolve(new Blob(["png"]))})}),await t(),expect(a("image_device-screen")).not.toBeNull(),expect(a("button_device-screen-left")).toBeNull()})}),describe("floating",()=>{const e=()=>a("container_device-screen"),s=()=>e().firstElementChild;it("titles the window with the model and firmware",async()=>{n({api:o(),floating:!0,firmwareVersion:"1.10.1"}),await t(),expect(e().textContent).toContain("Stax - 1.10.1"),expect(e().style.width).toBe("224px")}),it("stops polling while collapsed",async()=>{const r=o();n({api:r,floating:!0,defaultCollapsed:!0}),await t(5e3),expect(r.screenshot).not.toHaveBeenCalled(),expect(a("button_open-app-Bitcoin")).toBeNull(),l(()=>a("button_toggle-device-screen").click()),await t(),expect(r.screenshot).toHaveBeenCalled(),expect(a("button_open-app-Bitcoin")).not.toBeNull()}),it("is dragged by its header",async()=>{n({api:o(),floating:!0}),await t(),i(s(),"pointerdown",{clientX:10,clientY:10}),i(s(),"pointermove",{clientX:110,clientY:60}),i(s(),"pointerup"),i(s(),"pointermove",{clientX:500,clientY:500}),expect(e().style.left).toBe("100px"),expect(e().style.top).toBe("50px")}),describe("when the viewport shrinks",()=>{const r={width:window.innerWidth,height:window.innerHeight},d=(h,w)=>l(()=>{Object.assign(window,{innerWidth:h,innerHeight:w}),window.dispatchEvent(new Event("resize"))});afterEach(()=>{Object.assign(window,{innerWidth:r.width,innerHeight:r.height})}),it("pulls a dragged window back on screen",async()=>{n({api:o(),floating:!0}),await t(),e().getBoundingClientRect=()=>({left:0,top:0,width:224,height:300}),i(s(),"pointerdown",{clientX:10,clientY:10}),i(s(),"pointermove",{clientX:610,clientY:410}),i(s(),"pointerup"),expect(e().style.left).toBe("600px"),d(500,500),expect(e().style.left).toBe("276px"),expect(e().style.top).toBe("200px")}),it("leaves a window that was never moved in its corner",async()=>{n({api:o(),floating:!0}),await t(),d(500,500),expect(e().style.left).toBe(""),expect(e().style.right).toBe("16px")})}),it("is not dragged from its button or with another mouse button",async()=>{n({api:o(),floating:!0}),await t(),i(a("button_toggle-device-screen"),"pointerdown"),i(s(),"pointerdown",{button:2}),i(s(),"pointermove",{clientX:110,clientY:60}),expect(e().style.left).toBe("")}),it("is resized from its edge, down to a minimum width",async()=>{n({api:o(),floating:!0}),await t(),e().getBoundingClientRect=()=>({left:100,top:80,width:224,height:300});const r=a("handle_resize-device-screen");i(r,"pointerdown",{clientX:324}),i(r,"pointermove",{clientX:424}),expect(e().style.width).toBe("324px"),expect(e().style.left).toBe("100px"),i(r,"pointermove",{clientX:0}),i(r,"pointerup"),i(r,"pointermove",{clientX:600}),expect(e().style.width).toBe("200px")})})});
2
- //# sourceMappingURL=DeviceScreen.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/DeviceScreen.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { type Device } from \"@ledgerhq/device-mockserver-client\";\nimport { type ScreenApi } from \"@ledgerhq/device-mockserver-react-core\";\n\nimport { DeviceScreen, type DeviceScreenProps } from \"./DeviceScreen\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\nconst DEVICE = {\n id: \"device-1\",\n device_type: \"stax\",\n apps: [{ name: \"Bitcoin\", version: \"2.5.0\" }],\n} as unknown as Device;\n\nconst anApi = (overrides: Partial<ScreenApi> = {}): ScreenApi => ({\n screenshot: vi.fn(() => Promise.resolve(null)),\n idle: vi.fn(() =>\n Promise.resolve({ kind: \"os-info\" as const, device: DEVICE }),\n ),\n pressButton: vi.fn(() => Promise.resolve()),\n touch: vi.fn(() => Promise.resolve()),\n openApp: vi.fn(() => Promise.resolve()),\n ...overrides,\n});\n\ndescribe(\"DeviceScreen\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n const query = (testId: string) =>\n container.querySelector<HTMLElement>(`[data-testid=\"${testId}\"]`);\n const render = (props: Partial<DeviceScreenProps> & { api: ScreenApi }) =>\n act(() => root.render(<DeviceScreen deviceType=\"stax\" {...props} />));\n const wait = (ms = 0) => act(() => vi.advanceTimersByTimeAsync(ms));\n const pointer = (target: Element, type: string, init: MouseEventInit = {}) =>\n act(() => {\n target.dispatchEvent(\n new MouseEvent(type, { bubbles: true, button: 0, ...init }),\n );\n });\n\n beforeEach(() => {\n vi.useFakeTimers();\n URL.createObjectURL = vi.fn(() => \"blob:frame\");\n URL.revokeObjectURL = vi.fn();\n HTMLElement.prototype.setPointerCapture = vi.fn();\n HTMLElement.prototype.releasePointerCapture = vi.fn();\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n describe(\"inline\", () => {\n it(\"shows a placeholder until the screen answers\", () => {\n render({ api: anApi({ screenshot: () => new Promise(() => {}) }) });\n\n expect(query(\"placeholder_device-screen-loading\")).not.toBeNull();\n });\n\n it(\"shows the live screen of a running app\", async () => {\n render({\n api: anApi({ screenshot: () => Promise.resolve(new Blob([\"png\"])) }),\n });\n await wait();\n\n expect(query(\"image_device-screen\")?.getAttribute(\"src\")).toBe(\n \"blob:frame\",\n );\n });\n\n it(\"shows the installed apps while no app runs\", async () => {\n render({ api: anApi() });\n await wait();\n\n expect(query(\"button_open-app-Bitcoin\")).not.toBeNull();\n });\n\n it(\"says why a device without an emulator has no screen\", async () => {\n render({ api: anApi(), deviceType: \"nanoS\" });\n await wait();\n\n expect(query(\"button_open-app-Bitcoin\")).not.toBeNull();\n expect(container.textContent).toContain(\n \"Speculos has no emulator for the Nano S\",\n );\n });\n\n it(\"says nothing about emulators for a device that has one\", async () => {\n render({ api: anApi() });\n await wait();\n\n expect(container.textContent).not.toContain(\"has no emulator\");\n });\n\n it(\"says there is no screen when the api has nothing to show instead\", async () => {\n render({ api: anApi({ idle: undefined }) });\n await wait();\n\n expect(container.textContent).toContain(\"No screen to capture\");\n });\n\n it(\"shows why the screen is unavailable\", async () => {\n render({\n api: anApi({ screenshot: () => Promise.reject(new Error(\"offline\")) }),\n });\n await wait();\n\n expect(container.textContent).toContain(\"Screen unavailable\");\n expect(container.textContent).toContain(\"offline\");\n });\n\n it(\"keeps the last frame through a few failures while live\", async () => {\n const screenshot = vi\n .fn<() => Promise<Blob | null>>()\n .mockResolvedValueOnce(new Blob([\"png\"]))\n .mockRejectedValue(new Error(\"app quitting\"));\n const failures = () => screenshot.mock.calls.length - 1;\n render({ api: anApi({ screenshot }) });\n await wait();\n\n while (failures() < 3) await wait(500);\n expect(query(\"image_device-screen\")).not.toBeNull();\n\n while (failures() < 4) await wait(500);\n expect(query(\"image_device-screen\")).toBeNull();\n expect(container.textContent).toContain(\"app quitting\");\n });\n\n it(\"drives a Nano with its buttons and refreshes after\", async () => {\n const api = anApi({\n screenshot: vi.fn(() => Promise.resolve(new Blob([\"png\"]))),\n });\n render({ api, deviceType: \"nanoX\" });\n await wait();\n\n pointer(query(\"button_device-screen-left\")!, \"pointerdown\");\n pointer(query(\"button_device-screen-left\")!, \"pointerup\");\n await wait();\n\n expect(api.pressButton).toHaveBeenCalledWith(\"left\", \"press-and-release\");\n expect(api.screenshot).toHaveBeenCalledTimes(2);\n });\n\n it(\"drives a touch device by its screen, without buttons\", async () => {\n render({\n api: anApi({ screenshot: () => Promise.resolve(new Blob([\"png\"])) }),\n });\n await wait();\n\n expect(query(\"image_device-screen\")).not.toBeNull();\n expect(query(\"button_device-screen-left\")).toBeNull();\n });\n });\n\n describe(\"floating\", () => {\n const windowElement = () => query(\"container_device-screen\")!;\n const header = () => windowElement().firstElementChild!;\n\n it(\"titles the window with the model and firmware\", async () => {\n render({ api: anApi(), floating: true, firmwareVersion: \"1.10.1\" });\n await wait();\n\n expect(windowElement().textContent).toContain(\"Stax - 1.10.1\");\n expect(windowElement().style.width).toBe(\"224px\");\n });\n\n it(\"stops polling while collapsed\", async () => {\n const api = anApi();\n render({ api, floating: true, defaultCollapsed: true });\n await wait(5000);\n\n expect(api.screenshot).not.toHaveBeenCalled();\n expect(query(\"button_open-app-Bitcoin\")).toBeNull();\n\n act(() => query(\"button_toggle-device-screen\")!.click());\n await wait();\n\n expect(api.screenshot).toHaveBeenCalled();\n expect(query(\"button_open-app-Bitcoin\")).not.toBeNull();\n });\n\n it(\"is dragged by its header\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n\n pointer(header(), \"pointerdown\", { clientX: 10, clientY: 10 });\n pointer(header(), \"pointermove\", { clientX: 110, clientY: 60 });\n pointer(header(), \"pointerup\");\n pointer(header(), \"pointermove\", { clientX: 500, clientY: 500 });\n\n expect(windowElement().style.left).toBe(\"100px\");\n expect(windowElement().style.top).toBe(\"50px\");\n });\n\n describe(\"when the viewport shrinks\", () => {\n const viewport = { width: window.innerWidth, height: window.innerHeight };\n const resizeViewport = (width: number, height: number) =>\n act(() => {\n Object.assign(window, { innerWidth: width, innerHeight: height });\n window.dispatchEvent(new Event(\"resize\"));\n });\n\n afterEach(() => {\n Object.assign(window, {\n innerWidth: viewport.width,\n innerHeight: viewport.height,\n });\n });\n\n it(\"pulls a dragged window back on screen\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n windowElement().getBoundingClientRect = () =>\n ({ left: 0, top: 0, width: 224, height: 300 }) as DOMRect;\n pointer(header(), \"pointerdown\", { clientX: 10, clientY: 10 });\n pointer(header(), \"pointermove\", { clientX: 610, clientY: 410 });\n pointer(header(), \"pointerup\");\n expect(windowElement().style.left).toBe(\"600px\");\n\n resizeViewport(500, 500);\n\n expect(windowElement().style.left).toBe(\"276px\");\n expect(windowElement().style.top).toBe(\"200px\");\n });\n\n it(\"leaves a window that was never moved in its corner\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n\n resizeViewport(500, 500);\n\n expect(windowElement().style.left).toBe(\"\");\n expect(windowElement().style.right).toBe(\"16px\");\n });\n });\n\n it(\"is not dragged from its button or with another mouse button\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n\n pointer(query(\"button_toggle-device-screen\")!, \"pointerdown\");\n pointer(header(), \"pointerdown\", { button: 2 });\n pointer(header(), \"pointermove\", { clientX: 110, clientY: 60 });\n\n expect(windowElement().style.left).toBe(\"\");\n });\n\n it(\"is resized from its edge, down to a minimum width\", async () => {\n render({ api: anApi(), floating: true });\n await wait();\n windowElement().getBoundingClientRect = () =>\n ({ left: 100, top: 80, width: 224, height: 300 }) as DOMRect;\n const handle = query(\"handle_resize-device-screen\")!;\n\n pointer(handle, \"pointerdown\", { clientX: 324 });\n pointer(handle, \"pointermove\", { clientX: 424 });\n expect(windowElement().style.width).toBe(\"324px\");\n expect(windowElement().style.left).toBe(\"100px\");\n\n pointer(handle, \"pointermove\", { clientX: 0 });\n pointer(handle, \"pointerup\");\n pointer(handle, \"pointermove\", { clientX: 600 });\n expect(windowElement().style.width).toBe(\"200px\");\n });\n });\n});\n"],
5
- "mappings": "AAAA,OAAOA,GAAS,OAAAC,MAAW,QAC3B,OAAS,cAAAC,MAA6B,mBAItC,OAAS,gBAAAC,MAA4C,iBAErD,OAAO,OAAO,WAAY,CAAE,yBAA0B,EAAK,CAAC,EAE5D,MAAMC,EAAS,CACb,GAAI,WACJ,YAAa,OACb,KAAM,CAAC,CAAE,KAAM,UAAW,QAAS,OAAQ,CAAC,CAC9C,EAEMC,EAAQ,CAACC,EAAgC,CAAC,KAAkB,CAChE,WAAY,GAAG,GAAG,IAAM,QAAQ,QAAQ,IAAI,CAAC,EAC7C,KAAM,GAAG,GAAG,IACV,QAAQ,QAAQ,CAAE,KAAM,UAAoB,OAAQF,CAAO,CAAC,CAC9D,EACA,YAAa,GAAG,GAAG,IAAM,QAAQ,QAAQ,CAAC,EAC1C,MAAO,GAAG,GAAG,IAAM,QAAQ,QAAQ,CAAC,EACpC,QAAS,GAAG,GAAG,IAAM,QAAQ,QAAQ,CAAC,EACtC,GAAGE,CACL,GAEA,SAAS,eAAgB,IAAM,CAC7B,IAAIC,EACAC,EAEJ,MAAMC,EAASC,GACbH,EAAU,cAA2B,iBAAiBG,CAAM,IAAI,EAC5DC,EAAUC,GACdX,EAAI,IAAMO,EAAK,OAAOR,EAAA,cAACG,EAAA,CAAa,WAAW,OAAQ,GAAGS,EAAO,CAAE,CAAC,EAChEC,EAAO,CAACC,EAAK,IAAMb,EAAI,IAAM,GAAG,yBAAyBa,CAAE,CAAC,EAC5DC,EAAU,CAACC,EAAiBC,EAAcC,EAAuB,CAAC,IACtEjB,EAAI,IAAM,CACRe,EAAO,cACL,IAAI,WAAWC,EAAM,CAAE,QAAS,GAAM,OAAQ,EAAG,GAAGC,CAAK,CAAC,CAC5D,CACF,CAAC,EAEH,WAAW,IAAM,CACf,GAAG,cAAc,EACjB,IAAI,gBAAkB,GAAG,GAAG,IAAM,YAAY,EAC9C,IAAI,gBAAkB,GAAG,GAAG,EAC5B,YAAY,UAAU,kBAAoB,GAAG,GAAG,EAChD,YAAY,UAAU,sBAAwB,GAAG,GAAG,EACpDX,EAAY,SAAS,cAAc,KAAK,EACxC,SAAS,KAAK,OAAOA,CAAS,EAC9BC,EAAON,EAAWK,CAAS,CAC7B,CAAC,EAED,UAAU,IAAM,CACdN,EAAI,IAAMO,EAAK,QAAQ,CAAC,EACxBD,EAAU,OAAO,EACjB,GAAG,cAAc,CACnB,CAAC,EAED,SAAS,SAAU,IAAM,CACvB,GAAG,+CAAgD,IAAM,CACvDI,EAAO,CAAE,IAAKN,EAAM,CAAE,WAAY,IAAM,IAAI,QAAQ,IAAM,CAAC,CAAC,CAAE,CAAC,CAAE,CAAC,EAElE,OAAOI,EAAM,mCAAmC,CAAC,EAAE,IAAI,SAAS,CAClE,CAAC,EAED,GAAG,yCAA0C,SAAY,CACvDE,EAAO,CACL,IAAKN,EAAM,CAAE,WAAY,IAAM,QAAQ,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CACrE,CAAC,EACD,MAAMQ,EAAK,EAEX,OAAOJ,EAAM,qBAAqB,GAAG,aAAa,KAAK,CAAC,EAAE,KACxD,YACF,CACF,CAAC,EAED,GAAG,6CAA8C,SAAY,CAC3DE,EAAO,CAAE,IAAKN,EAAM,CAAE,CAAC,EACvB,MAAMQ,EAAK,EAEX,OAAOJ,EAAM,yBAAyB,CAAC,EAAE,IAAI,SAAS,CACxD,CAAC,EAED,GAAG,sDAAuD,SAAY,CACpEE,EAAO,CAAE,IAAKN,EAAM,EAAG,WAAY,OAAQ,CAAC,EAC5C,MAAMQ,EAAK,EAEX,OAAOJ,EAAM,yBAAyB,CAAC,EAAE,IAAI,SAAS,EACtD,OAAOF,EAAU,WAAW,EAAE,UAC5B,yCACF,CACF,CAAC,EAED,GAAG,yDAA0D,SAAY,CACvEI,EAAO,CAAE,IAAKN,EAAM,CAAE,CAAC,EACvB,MAAMQ,EAAK,EAEX,OAAON,EAAU,WAAW,EAAE,IAAI,UAAU,iBAAiB,CAC/D,CAAC,EAED,GAAG,mEAAoE,SAAY,CACjFI,EAAO,CAAE,IAAKN,EAAM,CAAE,KAAM,MAAU,CAAC,CAAE,CAAC,EAC1C,MAAMQ,EAAK,EAEX,OAAON,EAAU,WAAW,EAAE,UAAU,sBAAsB,CAChE,CAAC,EAED,GAAG,sCAAuC,SAAY,CACpDI,EAAO,CACL,IAAKN,EAAM,CAAE,WAAY,IAAM,QAAQ,OAAO,IAAI,MAAM,SAAS,CAAC,CAAE,CAAC,CACvE,CAAC,EACD,MAAMQ,EAAK,EAEX,OAAON,EAAU,WAAW,EAAE,UAAU,oBAAoB,EAC5D,OAAOA,EAAU,WAAW,EAAE,UAAU,SAAS,CACnD,CAAC,EAED,GAAG,yDAA0D,SAAY,CACvE,MAAMY,EAAa,GAChB,GAA+B,EAC/B,sBAAsB,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EACvC,kBAAkB,IAAI,MAAM,cAAc,CAAC,EACxCC,EAAW,IAAMD,EAAW,KAAK,MAAM,OAAS,EAItD,IAHAR,EAAO,CAAE,IAAKN,EAAM,CAAE,WAAAc,CAAW,CAAC,CAAE,CAAC,EACrC,MAAMN,EAAK,EAEJO,EAAS,EAAI,GAAG,MAAMP,EAAK,GAAG,EAGrC,IAFA,OAAOJ,EAAM,qBAAqB,CAAC,EAAE,IAAI,SAAS,EAE3CW,EAAS,EAAI,GAAG,MAAMP,EAAK,GAAG,EACrC,OAAOJ,EAAM,qBAAqB,CAAC,EAAE,SAAS,EAC9C,OAAOF,EAAU,WAAW,EAAE,UAAU,cAAc,CACxD,CAAC,EAED,GAAG,qDAAsD,SAAY,CACnE,MAAMc,EAAMhB,EAAM,CAChB,WAAY,GAAG,GAAG,IAAM,QAAQ,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAC5D,CAAC,EACDM,EAAO,CAAE,IAAAU,EAAK,WAAY,OAAQ,CAAC,EACnC,MAAMR,EAAK,EAEXE,EAAQN,EAAM,2BAA2B,EAAI,aAAa,EAC1DM,EAAQN,EAAM,2BAA2B,EAAI,WAAW,EACxD,MAAMI,EAAK,EAEX,OAAOQ,EAAI,WAAW,EAAE,qBAAqB,OAAQ,mBAAmB,EACxE,OAAOA,EAAI,UAAU,EAAE,sBAAsB,CAAC,CAChD,CAAC,EAED,GAAG,uDAAwD,SAAY,CACrEV,EAAO,CACL,IAAKN,EAAM,CAAE,WAAY,IAAM,QAAQ,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CACrE,CAAC,EACD,MAAMQ,EAAK,EAEX,OAAOJ,EAAM,qBAAqB,CAAC,EAAE,IAAI,SAAS,EAClD,OAAOA,EAAM,2BAA2B,CAAC,EAAE,SAAS,CACtD,CAAC,CACH,CAAC,EAED,SAAS,WAAY,IAAM,CACzB,MAAMa,EAAgB,IAAMb,EAAM,yBAAyB,EACrDc,EAAS,IAAMD,EAAc,EAAE,kBAErC,GAAG,gDAAiD,SAAY,CAC9DX,EAAO,CAAE,IAAKN,EAAM,EAAG,SAAU,GAAM,gBAAiB,QAAS,CAAC,EAClE,MAAMQ,EAAK,EAEX,OAAOS,EAAc,EAAE,WAAW,EAAE,UAAU,eAAe,EAC7D,OAAOA,EAAc,EAAE,MAAM,KAAK,EAAE,KAAK,OAAO,CAClD,CAAC,EAED,GAAG,gCAAiC,SAAY,CAC9C,MAAMD,EAAMhB,EAAM,EAClBM,EAAO,CAAE,IAAAU,EAAK,SAAU,GAAM,iBAAkB,EAAK,CAAC,EACtD,MAAMR,EAAK,GAAI,EAEf,OAAOQ,EAAI,UAAU,EAAE,IAAI,iBAAiB,EAC5C,OAAOZ,EAAM,yBAAyB,CAAC,EAAE,SAAS,EAElDR,EAAI,IAAMQ,EAAM,6BAA6B,EAAG,MAAM,CAAC,EACvD,MAAMI,EAAK,EAEX,OAAOQ,EAAI,UAAU,EAAE,iBAAiB,EACxC,OAAOZ,EAAM,yBAAyB,CAAC,EAAE,IAAI,SAAS,CACxD,CAAC,EAED,GAAG,2BAA4B,SAAY,CACzCE,EAAO,CAAE,IAAKN,EAAM,EAAG,SAAU,EAAK,CAAC,EACvC,MAAMQ,EAAK,EAEXE,EAAQQ,EAAO,EAAG,cAAe,CAAE,QAAS,GAAI,QAAS,EAAG,CAAC,EAC7DR,EAAQQ,EAAO,EAAG,cAAe,CAAE,QAAS,IAAK,QAAS,EAAG,CAAC,EAC9DR,EAAQQ,EAAO,EAAG,WAAW,EAC7BR,EAAQQ,EAAO,EAAG,cAAe,CAAE,QAAS,IAAK,QAAS,GAAI,CAAC,EAE/D,OAAOD,EAAc,EAAE,MAAM,IAAI,EAAE,KAAK,OAAO,EAC/C,OAAOA,EAAc,EAAE,MAAM,GAAG,EAAE,KAAK,MAAM,CAC/C,CAAC,EAED,SAAS,4BAA6B,IAAM,CAC1C,MAAME,EAAW,CAAE,MAAO,OAAO,WAAY,OAAQ,OAAO,WAAY,EAClEC,EAAiB,CAACC,EAAeC,IACrC1B,EAAI,IAAM,CACR,OAAO,OAAO,OAAQ,CAAE,WAAYyB,EAAO,YAAaC,CAAO,CAAC,EAChE,OAAO,cAAc,IAAI,MAAM,QAAQ,CAAC,CAC1C,CAAC,EAEH,UAAU,IAAM,CACd,OAAO,OAAO,OAAQ,CACpB,WAAYH,EAAS,MACrB,YAAaA,EAAS,MACxB,CAAC,CACH,CAAC,EAED,GAAG,wCAAyC,SAAY,CACtDb,EAAO,CAAE,IAAKN,EAAM,EAAG,SAAU,EAAK,CAAC,EACvC,MAAMQ,EAAK,EACXS,EAAc,EAAE,sBAAwB,KACrC,CAAE,KAAM,EAAG,IAAK,EAAG,MAAO,IAAK,OAAQ,GAAI,GAC9CP,EAAQQ,EAAO,EAAG,cAAe,CAAE,QAAS,GAAI,QAAS,EAAG,CAAC,EAC7DR,EAAQQ,EAAO,EAAG,cAAe,CAAE,QAAS,IAAK,QAAS,GAAI,CAAC,EAC/DR,EAAQQ,EAAO,EAAG,WAAW,EAC7B,OAAOD,EAAc,EAAE,MAAM,IAAI,EAAE,KAAK,OAAO,EAE/CG,EAAe,IAAK,GAAG,EAEvB,OAAOH,EAAc,EAAE,MAAM,IAAI,EAAE,KAAK,OAAO,EAC/C,OAAOA,EAAc,EAAE,MAAM,GAAG,EAAE,KAAK,OAAO,CAChD,CAAC,EAED,GAAG,qDAAsD,SAAY,CACnEX,EAAO,CAAE,IAAKN,EAAM,EAAG,SAAU,EAAK,CAAC,EACvC,MAAMQ,EAAK,EAEXY,EAAe,IAAK,GAAG,EAEvB,OAAOH,EAAc,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,EAC1C,OAAOA,EAAc,EAAE,MAAM,KAAK,EAAE,KAAK,MAAM,CACjD,CAAC,CACH,CAAC,EAED,GAAG,8DAA+D,SAAY,CAC5EX,EAAO,CAAE,IAAKN,EAAM,EAAG,SAAU,EAAK,CAAC,EACvC,MAAMQ,EAAK,EAEXE,EAAQN,EAAM,6BAA6B,EAAI,aAAa,EAC5DM,EAAQQ,EAAO,EAAG,cAAe,CAAE,OAAQ,CAAE,CAAC,EAC9CR,EAAQQ,EAAO,EAAG,cAAe,CAAE,QAAS,IAAK,QAAS,EAAG,CAAC,EAE9D,OAAOD,EAAc,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,CAC5C,CAAC,EAED,GAAG,oDAAqD,SAAY,CAClEX,EAAO,CAAE,IAAKN,EAAM,EAAG,SAAU,EAAK,CAAC,EACvC,MAAMQ,EAAK,EACXS,EAAc,EAAE,sBAAwB,KACrC,CAAE,KAAM,IAAK,IAAK,GAAI,MAAO,IAAK,OAAQ,GAAI,GACjD,MAAMM,EAASnB,EAAM,6BAA6B,EAElDM,EAAQa,EAAQ,cAAe,CAAE,QAAS,GAAI,CAAC,EAC/Cb,EAAQa,EAAQ,cAAe,CAAE,QAAS,GAAI,CAAC,EAC/C,OAAON,EAAc,EAAE,MAAM,KAAK,EAAE,KAAK,OAAO,EAChD,OAAOA,EAAc,EAAE,MAAM,IAAI,EAAE,KAAK,OAAO,EAE/CP,EAAQa,EAAQ,cAAe,CAAE,QAAS,CAAE,CAAC,EAC7Cb,EAAQa,EAAQ,WAAW,EAC3Bb,EAAQa,EAAQ,cAAe,CAAE,QAAS,GAAI,CAAC,EAC/C,OAAON,EAAc,EAAE,MAAM,KAAK,EAAE,KAAK,OAAO,CAClD,CAAC,CACH,CAAC,CACH,CAAC",
6
- "names": ["React", "act", "createRoot", "DeviceScreen", "DEVICE", "anApi", "overrides", "container", "root", "query", "testId", "render", "props", "wait", "ms", "pointer", "target", "type", "init", "screenshot", "failures", "api", "windowElement", "header", "viewport", "resizeViewport", "width", "height", "handle"]
7
- }
@@ -1,2 +0,0 @@
1
- import p,{act as o}from"react";import{createRoot as c}from"react-dom/client";import{DeviceScreenButtons as u}from"./DeviceScreenButtons";Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});describe("DeviceScreenButtons",()=>{let r,i;const t=vi.fn(),e=s=>r.querySelector(`[data-testid="button_device-screen-${s}"]`),n=(s,l,d={})=>o(()=>{s.dispatchEvent(new MouseEvent(l,{bubbles:!0,button:0,...d}))}),a=(s,l,d)=>o(()=>{s.dispatchEvent(new KeyboardEvent(l,{bubbles:!0,key:d}))});beforeEach(()=>{vi.useFakeTimers(),t.mockReset(),HTMLElement.prototype.setPointerCapture=vi.fn(),r=document.createElement("div"),document.body.append(r),i=c(r),o(()=>i.render(p.createElement(u,{onPress:t})))}),afterEach(()=>{o(()=>i.unmount()),r.remove(),vi.useRealTimers()}),it("sends a quick click as one press-and-release",()=>{n(e("left"),"pointerdown"),n(e("left"),"pointerup"),expect(t).toHaveBeenCalledOnce(),expect(t).toHaveBeenCalledWith("left","press-and-release")}),it("sends a hold as a press then a release",()=>{n(e("both"),"pointerdown"),o(()=>{vi.advanceTimersByTime(200)}),n(e("both"),"pointerup"),expect(t.mock.calls).toEqual([["both","press"],["both","release"]])}),it("ignores buttons other than the main one",()=>{n(e("right"),"pointerdown",{button:2}),n(e("right"),"pointerup",{button:2}),expect(t).not.toHaveBeenCalled()}),it("handles one button at a time",()=>{n(e("left"),"pointerdown"),n(e("right"),"pointerdown"),n(e("left"),"pointerup"),expect(t).toHaveBeenCalledWith("left","press-and-release"),expect(t).toHaveBeenCalledOnce()}),it("drives the buttons from the keyboard",()=>{a(e("right"),"keydown","Enter"),a(e("right"),"keyup","Enter"),a(e("right"),"keydown","a"),expect(t).toHaveBeenCalledOnce(),expect(t).toHaveBeenCalledWith("right","press-and-release")}),it("releases a held button when unmounted",()=>{n(e("left"),"pointerdown"),o(()=>{vi.advanceTimersByTime(200)}),o(()=>i.render(p.createElement(p.Fragment,null))),expect(t).toHaveBeenLastCalledWith("left","release")})});
2
- //# sourceMappingURL=DeviceScreenButtons.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/DeviceScreenButtons.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\n\nimport { DeviceScreenButtons } from \"./DeviceScreenButtons\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\ndescribe(\"DeviceScreenButtons\", () => {\n let container: HTMLDivElement;\n let root: Root;\n const onPress = vi.fn();\n\n const button = (name: string) =>\n container.querySelector<HTMLButtonElement>(\n `[data-testid=\"button_device-screen-${name}\"]`,\n )!;\n const pointer = (target: Element, type: string, init: MouseEventInit = {}) =>\n act(() => {\n target.dispatchEvent(\n new MouseEvent(type, { bubbles: true, button: 0, ...init }),\n );\n });\n const key = (target: Element, type: string, value: string) =>\n act(() => {\n target.dispatchEvent(\n new KeyboardEvent(type, { bubbles: true, key: value }),\n );\n });\n\n beforeEach(() => {\n vi.useFakeTimers();\n onPress.mockReset();\n HTMLElement.prototype.setPointerCapture = vi.fn();\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n act(() => root.render(<DeviceScreenButtons onPress={onPress} />));\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n it(\"sends a quick click as one press-and-release\", () => {\n pointer(button(\"left\"), \"pointerdown\");\n pointer(button(\"left\"), \"pointerup\");\n\n expect(onPress).toHaveBeenCalledOnce();\n expect(onPress).toHaveBeenCalledWith(\"left\", \"press-and-release\");\n });\n\n it(\"sends a hold as a press then a release\", () => {\n pointer(button(\"both\"), \"pointerdown\");\n act(() => {\n vi.advanceTimersByTime(200);\n });\n pointer(button(\"both\"), \"pointerup\");\n\n expect(onPress.mock.calls).toEqual([\n [\"both\", \"press\"],\n [\"both\", \"release\"],\n ]);\n });\n\n it(\"ignores buttons other than the main one\", () => {\n pointer(button(\"right\"), \"pointerdown\", { button: 2 });\n pointer(button(\"right\"), \"pointerup\", { button: 2 });\n\n expect(onPress).not.toHaveBeenCalled();\n });\n\n it(\"handles one button at a time\", () => {\n pointer(button(\"left\"), \"pointerdown\");\n pointer(button(\"right\"), \"pointerdown\");\n pointer(button(\"left\"), \"pointerup\");\n\n expect(onPress).toHaveBeenCalledWith(\"left\", \"press-and-release\");\n expect(onPress).toHaveBeenCalledOnce();\n });\n\n it(\"drives the buttons from the keyboard\", () => {\n key(button(\"right\"), \"keydown\", \"Enter\");\n key(button(\"right\"), \"keyup\", \"Enter\");\n key(button(\"right\"), \"keydown\", \"a\");\n\n expect(onPress).toHaveBeenCalledOnce();\n expect(onPress).toHaveBeenCalledWith(\"right\", \"press-and-release\");\n });\n\n it(\"releases a held button when unmounted\", () => {\n pointer(button(\"left\"), \"pointerdown\");\n act(() => {\n vi.advanceTimersByTime(200);\n });\n act(() => root.render(<></>));\n\n expect(onPress).toHaveBeenLastCalledWith(\"left\", \"release\");\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["React", "act", "createRoot", "DeviceScreenButtons", "container", "root", "onPress", "button", "name", "pointer", "target", "type", "init", "key", "value"]
7
- }
@@ -1,2 +0,0 @@
1
- import s,{act as o}from"react";import{createRoot as u}from"react-dom/client";import{HOLD_THRESHOLD_MS as d}from"@ledgerhq/device-mockserver-react-core";import{DeviceScreenImage as m}from"./DeviceScreenImage";Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});describe("DeviceScreenImage",()=>{let i,c;const e=vi.fn(),r=()=>i.querySelector('[data-testid="image_device-screen"]'),n=l=>o(()=>c.render(s.createElement(m,{src:"blob:1",onTouch:l}))),t=(l,p={})=>o(()=>{r().dispatchEvent(new MouseEvent(l,{bubbles:!0,button:0,...p}))}),a=()=>{Object.defineProperty(r(),"naturalWidth",{value:400}),Object.defineProperty(r(),"naturalHeight",{value:600}),r().getBoundingClientRect=()=>({left:0,top:0,width:200,height:300})};beforeEach(()=>{vi.useFakeTimers(),e.mockReset(),HTMLElement.prototype.setPointerCapture=vi.fn(),HTMLElement.prototype.releasePointerCapture=vi.fn(),i=document.createElement("div"),document.body.append(i),c=u(i)}),afterEach(()=>{o(()=>c.unmount()),i.remove(),vi.useRealTimers()}),it("maps a tap to device pixels",()=>{n(e),a(),t("pointerdown",{clientX:50,clientY:150}),t("pointerup",{clientX:190,clientY:10}),expect(e).toHaveBeenCalledExactlyOnceWith(100,300,"press-and-release")}),it("releases a hold where it went down",()=>{n(e),a(),t("pointerdown",{clientX:50,clientY:150}),o(()=>{vi.advanceTimersByTime(d)}),t("pointerup",{clientX:190,clientY:10}),expect(e.mock.calls).toEqual([[100,300,"press"],[100,300,"release"]])}),it("clamps a touch on the far edge to the last pixel",()=>{n(e),a(),t("pointerdown",{clientX:200,clientY:300}),t("pointerup"),expect(e).toHaveBeenCalledWith(399,599,"press-and-release")}),it("ignores touches before the image has a size",()=>{n(e),t("pointerdown",{clientX:10,clientY:10}),t("pointerup"),expect(e).not.toHaveBeenCalled()}),it("ignores touches on a button-driven device",()=>{n(),a(),t("pointerdown",{clientX:10,clientY:10}),expect(e).not.toHaveBeenCalled()}),it("releases a held touch when unmounted",()=>{n(e),a(),t("pointerdown",{clientX:50,clientY:150}),o(()=>{vi.advanceTimersByTime(d)}),o(()=>c.render(s.createElement(s.Fragment,null))),expect(e).toHaveBeenLastCalledWith(100,300,"release")}),it("says so when the screenshot cannot be decoded",()=>{n(e),o(()=>{r().dispatchEvent(new Event("error"))}),expect(i.querySelector('[data-testid="text_device-screen-undecodable"]')).not.toBeNull()})});
2
- //# sourceMappingURL=DeviceScreenImage.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/DeviceScreenImage.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { HOLD_THRESHOLD_MS } from \"@ledgerhq/device-mockserver-react-core\";\n\nimport { DeviceScreenImage } from \"./DeviceScreenImage\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\ndescribe(\"DeviceScreenImage\", () => {\n let container: HTMLDivElement;\n let root: Root;\n const onTouch = vi.fn();\n\n const image = () =>\n container.querySelector<HTMLImageElement>(\n '[data-testid=\"image_device-screen\"]',\n )!;\n const render = (touch?: typeof onTouch) =>\n act(() => root.render(<DeviceScreenImage src=\"blob:1\" onTouch={touch} />));\n const pointer = (type: string, init: MouseEventInit = {}) =>\n act(() => {\n image().dispatchEvent(\n new MouseEvent(type, { bubbles: true, button: 0, ...init }),\n );\n });\n /** A 400x600 screen drawn at 200x300 from the page's top left corner. */\n const sizeImage = () => {\n Object.defineProperty(image(), \"naturalWidth\", { value: 400 });\n Object.defineProperty(image(), \"naturalHeight\", { value: 600 });\n image().getBoundingClientRect = () =>\n ({ left: 0, top: 0, width: 200, height: 300 }) as DOMRect;\n };\n\n beforeEach(() => {\n vi.useFakeTimers();\n onTouch.mockReset();\n HTMLElement.prototype.setPointerCapture = vi.fn();\n HTMLElement.prototype.releasePointerCapture = vi.fn();\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n it(\"maps a tap to device pixels\", () => {\n render(onTouch);\n sizeImage();\n\n pointer(\"pointerdown\", { clientX: 50, clientY: 150 });\n pointer(\"pointerup\", { clientX: 190, clientY: 10 });\n\n expect(onTouch).toHaveBeenCalledExactlyOnceWith(\n 100,\n 300,\n \"press-and-release\",\n );\n });\n\n it(\"releases a hold where it went down\", () => {\n render(onTouch);\n sizeImage();\n\n pointer(\"pointerdown\", { clientX: 50, clientY: 150 });\n act(() => {\n vi.advanceTimersByTime(HOLD_THRESHOLD_MS);\n });\n pointer(\"pointerup\", { clientX: 190, clientY: 10 });\n\n expect(onTouch.mock.calls).toEqual([\n [100, 300, \"press\"],\n [100, 300, \"release\"],\n ]);\n });\n\n it(\"clamps a touch on the far edge to the last pixel\", () => {\n render(onTouch);\n sizeImage();\n\n pointer(\"pointerdown\", { clientX: 200, clientY: 300 });\n pointer(\"pointerup\");\n\n expect(onTouch).toHaveBeenCalledWith(399, 599, \"press-and-release\");\n });\n\n it(\"ignores touches before the image has a size\", () => {\n render(onTouch);\n\n pointer(\"pointerdown\", { clientX: 10, clientY: 10 });\n pointer(\"pointerup\");\n\n expect(onTouch).not.toHaveBeenCalled();\n });\n\n it(\"ignores touches on a button-driven device\", () => {\n render();\n sizeImage();\n\n pointer(\"pointerdown\", { clientX: 10, clientY: 10 });\n\n expect(onTouch).not.toHaveBeenCalled();\n });\n\n it(\"releases a held touch when unmounted\", () => {\n render(onTouch);\n sizeImage();\n pointer(\"pointerdown\", { clientX: 50, clientY: 150 });\n act(() => {\n vi.advanceTimersByTime(HOLD_THRESHOLD_MS);\n });\n\n act(() => root.render(<></>));\n\n expect(onTouch).toHaveBeenLastCalledWith(100, 300, \"release\");\n });\n\n it(\"says so when the screenshot cannot be decoded\", () => {\n render(onTouch);\n\n act(() => {\n image().dispatchEvent(new Event(\"error\"));\n });\n\n expect(\n container.querySelector('[data-testid=\"text_device-screen-undecodable\"]'),\n ).not.toBeNull();\n });\n});\n"],
5
- "mappings": "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",
6
- "names": ["React", "act", "createRoot", "HOLD_THRESHOLD_MS", "DeviceScreenImage", "container", "root", "onTouch", "image", "render", "touch", "pointer", "type", "init", "sizeImage"]
7
- }
@@ -1,2 +0,0 @@
1
- import r,{act as o}from"react";import{createRoot as s}from"react-dom/client";import{MockClient as c}from"@ledgerhq/device-mockserver-client";import{MockServerDevice as a}from"./MockServerDevice";Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:!0});vi.mock("@ledgerhq/device-mockserver-client",()=>({MockClient:vi.fn()}));describe("MockServerDevice",()=>{let e,n;const t=vi.fn();beforeEach(()=>{vi.useFakeTimers(),t.mockReset(),vi.mocked(c).mockImplementation(()=>({getDevice:t,getScreenshot:()=>new Promise(()=>{})})),e=document.createElement("div"),document.body.append(e),n=s(e)}),afterEach(()=>{o(()=>n.unmount()),e.remove(),vi.useRealTimers()});const i=()=>o(()=>n.render(r.createElement(a,{url:"http://mock",token:"session-token",deviceId:"device-1",floating:!0})));it("renders nothing until the device's model is known",()=>{t.mockReturnValue(new Promise(()=>{})),i(),expect(e.childElementCount).toBe(0)}),it("shows the device's screen in its session",async()=>{t.mockResolvedValue({id:"device-1",device_type:"flex",firmware_version:"1.6.1"}),i(),await o(()=>vi.advanceTimersByTimeAsync(0)),expect(c).toHaveBeenCalledWith("http://mock",{token:"session-token"}),expect(t).toHaveBeenCalledWith("device-1"),expect(e.textContent).toContain("Flex - 1.6.1")}),it("still shows the screen when the device cannot be read",async()=>{t.mockRejectedValue(new Error("offline")),i(),await o(()=>vi.advanceTimersByTimeAsync(0)),expect(e.querySelector('[data-testid="container_device-screen"]')).not.toBeNull()})});
2
- //# sourceMappingURL=MockServerDevice.test.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/MockServerDevice.test.tsx"],
4
- "sourcesContent": ["import React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { MockClient } from \"@ledgerhq/device-mockserver-client\";\n\nimport { MockServerDevice } from \"./MockServerDevice\";\n\nObject.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true });\n\nvi.mock(\"@ledgerhq/device-mockserver-client\", () => ({\n MockClient: vi.fn(),\n}));\n\ndescribe(\"MockServerDevice\", () => {\n let container: HTMLDivElement;\n let root: Root;\n const getDevice = vi.fn();\n\n beforeEach(() => {\n vi.useFakeTimers();\n getDevice.mockReset();\n vi.mocked(MockClient).mockImplementation(\n () =>\n ({\n getDevice,\n getScreenshot: () => new Promise(() => {}),\n }) as unknown as MockClient,\n );\n container = document.createElement(\"div\");\n document.body.append(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n });\n\n const render = () =>\n act(() =>\n root.render(\n <MockServerDevice\n url=\"http://mock\"\n token=\"session-token\"\n deviceId=\"device-1\"\n floating\n />,\n ),\n );\n\n it(\"renders nothing until the device's model is known\", () => {\n getDevice.mockReturnValue(new Promise(() => {}));\n\n render();\n\n expect(container.childElementCount).toBe(0);\n });\n\n it(\"shows the device's screen in its session\", async () => {\n getDevice.mockResolvedValue({\n id: \"device-1\",\n device_type: \"flex\",\n firmware_version: \"1.6.1\",\n });\n\n render();\n await act(() => vi.advanceTimersByTimeAsync(0));\n\n expect(MockClient).toHaveBeenCalledWith(\"http://mock\", {\n token: \"session-token\",\n });\n expect(getDevice).toHaveBeenCalledWith(\"device-1\");\n expect(container.textContent).toContain(\"Flex - 1.6.1\");\n });\n\n it(\"still shows the screen when the device cannot be read\", async () => {\n getDevice.mockRejectedValue(new Error(\"offline\"));\n\n render();\n await act(() => vi.advanceTimersByTimeAsync(0));\n\n expect(\n container.querySelector('[data-testid=\"container_device-screen\"]'),\n ).not.toBeNull();\n });\n});\n"],
5
- "mappings": "AAAA,OAAOA,GAAS,OAAAC,MAAW,QAC3B,OAAS,cAAAC,MAA6B,mBACtC,OAAS,cAAAC,MAAkB,qCAE3B,OAAS,oBAAAC,MAAwB,qBAEjC,OAAO,OAAO,WAAY,CAAE,yBAA0B,EAAK,CAAC,EAE5D,GAAG,KAAK,qCAAsC,KAAO,CACnD,WAAY,GAAG,GAAG,CACpB,EAAE,EAEF,SAAS,mBAAoB,IAAM,CACjC,IAAIC,EACAC,EACJ,MAAMC,EAAY,GAAG,GAAG,EAExB,WAAW,IAAM,CACf,GAAG,cAAc,EACjBA,EAAU,UAAU,EACpB,GAAG,OAAOJ,CAAU,EAAE,mBACpB,KACG,CACC,UAAAI,EACA,cAAe,IAAM,IAAI,QAAQ,IAAM,CAAC,CAAC,CAC3C,EACJ,EACAF,EAAY,SAAS,cAAc,KAAK,EACxC,SAAS,KAAK,OAAOA,CAAS,EAC9BC,EAAOJ,EAAWG,CAAS,CAC7B,CAAC,EAED,UAAU,IAAM,CACdJ,EAAI,IAAMK,EAAK,QAAQ,CAAC,EACxBD,EAAU,OAAO,EACjB,GAAG,cAAc,CACnB,CAAC,EAED,MAAMG,EAAS,IACbP,EAAI,IACFK,EAAK,OACHN,EAAA,cAACI,EAAA,CACC,IAAI,cACJ,MAAM,gBACN,SAAS,WACT,SAAQ,GACV,CACF,CACF,EAEF,GAAG,oDAAqD,IAAM,CAC5DG,EAAU,gBAAgB,IAAI,QAAQ,IAAM,CAAC,CAAC,CAAC,EAE/CC,EAAO,EAEP,OAAOH,EAAU,iBAAiB,EAAE,KAAK,CAAC,CAC5C,CAAC,EAED,GAAG,2CAA4C,SAAY,CACzDE,EAAU,kBAAkB,CAC1B,GAAI,WACJ,YAAa,OACb,iBAAkB,OACpB,CAAC,EAEDC,EAAO,EACP,MAAMP,EAAI,IAAM,GAAG,yBAAyB,CAAC,CAAC,EAE9C,OAAOE,CAAU,EAAE,qBAAqB,cAAe,CACrD,MAAO,eACT,CAAC,EACD,OAAOI,CAAS,EAAE,qBAAqB,UAAU,EACjD,OAAOF,EAAU,WAAW,EAAE,UAAU,cAAc,CACxD,CAAC,EAED,GAAG,wDAAyD,SAAY,CACtEE,EAAU,kBAAkB,IAAI,MAAM,SAAS,CAAC,EAEhDC,EAAO,EACP,MAAMP,EAAI,IAAM,GAAG,yBAAyB,CAAC,CAAC,EAE9C,OACEI,EAAU,cAAc,yCAAyC,CACnE,EAAE,IAAI,SAAS,CACjB,CAAC,CACH,CAAC",
6
- "names": ["React", "act", "createRoot", "MockClient", "MockServerDevice", "container", "root", "getDevice", "render"]
7
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=DeviceOsInfo.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DeviceOsInfo.test.d.ts","sourceRoot":"","sources":["../../../src/DeviceOsInfo.test.tsx"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=DeviceScreen.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DeviceScreen.test.d.ts","sourceRoot":"","sources":["../../../src/DeviceScreen.test.tsx"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=DeviceScreenButtons.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DeviceScreenButtons.test.d.ts","sourceRoot":"","sources":["../../../src/DeviceScreenButtons.test.tsx"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=DeviceScreenImage.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DeviceScreenImage.test.d.ts","sourceRoot":"","sources":["../../../src/DeviceScreenImage.test.tsx"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=MockServerDevice.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MockServerDevice.test.d.ts","sourceRoot":"","sources":["../../../src/MockServerDevice.test.tsx"],"names":[],"mappings":""}