Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,50 @@ else
endif
$(TARGET_OK)

.PHONY: tests-sandbox
tests-sandbox: .require-compose ## [Tests][docker] Runs jsdom, browser and e2e tests for v1-sandbox
$(TARGET_HEADER)
$(COMPOSE) run --rm --user "$$(id -u):$$(id -g)" playwright \
yarn workspace @retailcrm/embed-ui-v1-sandbox test:all
$(TARGET_OK)

.PHONY: tests-sandbox-browser
tests-sandbox-browser: .require-compose ## [Tests][docker] Run browser mod tests for v1-sandbox
$(TARGET_HEADER)
ifdef cli
@$(COMPOSE) run --rm --user "$$(id -u):$$(id -g)" playwright \
yarn workspace @retailcrm/embed-ui-v1-sandbox test:browser $(cli) --passWithNoTests
else
@$(COMPOSE) run --rm --user "$$(id -u):$$(id -g)" playwright \
yarn workspace @retailcrm/embed-ui-v1-sandbox test:browser
endif
$(TARGET_OK)


.PHONY: tests-sandbox-e2e
tests-sandbox-e2e: .require-compose ## [Tests][docker] Run e2e tests for v1-sandbox
$(TARGET_HEADER)
ifdef cli
@$(COMPOSE) run --rm --user "$$(id -u):$$(id -g)" playwright \
yarn workspace @retailcrm/embed-ui-v1-sandbox test:e2e $(cli)
else
@$(COMPOSE) run --rm --user "$$(id -u):$$(id -g)" playwright \
yarn workspace @retailcrm/embed-ui-v1-sandbox test:e2e
endif
$(TARGET_OK)

.PHONY: tests-sandbox-jsdom
tests-sandbox-jsdom: .require-compose ## [Tests][docker] Run jsdom tests for v1-sandbox
$(TARGET_HEADER)
ifdef cli
@$(COMPOSE) run --rm --user "$$(id -u):$$(id -g)" playwright \
yarn workspace @retailcrm/embed-ui-v1-sandbox test:jsdom $(cli) --passWithNoTests
else
@$(COMPOSE) run --rm --user "$$(id -u):$$(id -g)" playwright \
yarn workspace @retailcrm/embed-ui-v1-sandbox test:jsdom
endif
$(TARGET_OK)

.PHONY: tests-browser
tests-browser: .require-compose ## [Tests][docker] Runs browser mode tests for all workspaces
$(TARGET_HEADER)
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ services:
environment:
- COREPACK_ENABLE_DOWNLOAD_PROMPT=0
- PATH=/project/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- HOME=/tmp
- COREPACK_HOME=/tmp/corepack
volumes:
- ./:/project
working_dir: /project
Expand Down
26 changes: 23 additions & 3 deletions packages/v1-sandbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,21 @@ npx @retailcrm/embed-ui-v1-sandbox serve
embed-ui-v1-sandbox serve --host 0.0.0.0 --port 4173
```

Откройте URL из вывода команды, укажите URL расширения
`%extension-url%/extension/%extension-id%`, выберите режим и fixture, затем нажмите `Apply`.
Откройте URL из вывода команды и вставьте runtime-дескриптор расширения:

```json
{
"code": "returnsModule",
"baseUrl": "https://extension.test",
"entrypoint": "/build/worker.js",
"pages": ["returns"],
"stylesheet": "/build/extension.css",
"targets": []
}
```

`entrypoint` и `stylesheet` разрешаются относительно `baseUrl`. JSON можно
вставить целиком либо заполнить те же поля отдельно в DevPanel.

## Применение в тестах

Expand Down Expand Up @@ -68,8 +81,15 @@ test('loads extension page in sandbox', async ({ page }) => {
await page.goto('/')

await launchSandboxExtension(page, {
descriptor: {
code: 'returnsModule',
baseUrl: 'https://extension.test',
entrypoint: '/build/worker.js',
pages: ['returns'],
stylesheet: '/build/extension.css',
targets: [],
},
fixture: 'order-basic',
manifestUrl: '%extension-url%/extension/%extension-id%',
mode: 'page',
pageCode: 'returns',
})
Expand Down
37 changes: 30 additions & 7 deletions packages/v1-sandbox/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,15 @@ HostAPI snapshot from `window.__CRM_EMBED_SANDBOX__`:

```ts
await page.goto(createSandboxPagePath({
extensionUrl: '%extension-url%/extension/%extension-id%',
descriptor: {
code: 'returnsModule',
baseUrl: 'https://extension.test',
entrypoint: '/build/worker.js',
pages: ['returns'],
stylesheet: '/build/extension.css',
targets: [],
},
pageCode: 'returns',
targets: ['order/card:common.after'],
}))

const snapshot = await readSandboxSnapshot(page)
Expand Down Expand Up @@ -156,24 +162,40 @@ from package delivery or a test process.

The sandbox app is controlled by query parameters:

- `manifestUrl`: full extension descriptor/entrypoint/script URL.
- `descriptor`: URL-encoded JSON runtime descriptor. This is the primary mode.
- `mode`: `widget` or `page`.
- `fixture`: sandbox fixture code, for example `order-basic`.
- `pageCode`: page runner code for `mode=page`.
- `targets`: comma-separated widget targets for `mode=widget`.
- `widgetId`: base widget instance id.
- `extensionUrl`: low-level fallback for direct worker entrypoints.

The runtime descriptor has exactly these fields:

```ts
type SandboxExtensionDescriptor = {
code: string
baseUrl: string
entrypoint: string
stylesheet: string | null
pages: string[]
targets: TargetName[]
}
```

`baseUrl` must be an absolute HTTP(S) URL. `entrypoint` and non-null
`stylesheet` may be relative to it or absolute. Unknown fields, including
`runner` and `uuid`, are rejected.

Example page URL:

```text
%sandbox-url%/?manifestUrl=%extension-url%/extension/%extension-id%&mode=page&pageCode=returns&fixture=order-basic
%sandbox-url%/?descriptor=%url-encoded-descriptor-json%&mode=page&pageCode=returns&fixture=order-basic
```

Example widget URL:

```text
%sandbox-url%/?manifestUrl=%extension-url%/extension/%extension-id%&mode=widget&targets=order/card:common.after&fixture=order-basic
%sandbox-url%/?descriptor=%url-encoded-descriptor-json%&mode=widget&targets=order/card:common.after&fixture=order-basic
```

## HostAPI HTTP Contract
Expand All @@ -184,7 +206,8 @@ Extensions call:
await host.httpCall('/returns', payload)
```

When the sandbox can infer the backend base from `manifestUrl`, it sends:
In descriptor mode the backend base is `baseUrl`; the call
above sends:

```text
POST %extension-url%/returns
Expand Down
46 changes: 37 additions & 9 deletions packages/v1-sandbox/docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,29 @@ Start the sandbox app:
npx @retailcrm/embed-ui-v1-sandbox serve
```

Open the printed URL and paste a full extension endpoint:
Open the printed URL and paste a runtime descriptor:

```text
%extension-url%/extension/%extension-id%
```json
{
"code": "promoModule",
"baseUrl": "http://web-extensions-server.simla.local",
"entrypoint": "/extension/8ebe1617-d609-43e4-b35a-fbfae011eee3/script",
"stylesheet": "/extension/8ebe1617-d609-43e4-b35a-fbfae011eee3/stylesheet",
"targets": [],
"pages": ["settings"],
}
```

Page runner direct URL:

```text
%sandbox-url%/?manifestUrl=%extension-url%/extension/%extension-id%&mode=page&pageCode=returns&fixture=order-basic
%sandbox-url%/?descriptor=%url-encoded-descriptor-json%&mode=page&pageCode=returns&fixture=order-basic
```

Widget runner direct URL:

```text
%sandbox-url%/?manifestUrl=%extension-url%/extension/%extension-id%&mode=widget&targets=order/card:common.after&fixture=order-basic
%sandbox-url%/?descriptor=%url-encoded-descriptor-json%&mode=widget&targets=order/card:common.after&fixture=order-basic
```

Use the DevPanel to switch fixtures, edit Context JSON, or change page/widget
Expand Down Expand Up @@ -88,8 +95,15 @@ afterEach(() => {

test('mounts page extension in browser mode', async () => {
sandbox = await launchSandboxExtension({
descriptor: {
baseUrl: new URL('/tests/fixtures/extensions/returnsModule/', window.location.href).href,
code: 'returnsModule',
entrypoint: 'index.ts',
pages: ['returns'],
stylesheet: null,
targets: [],
},
fixture: 'order-basic',
manifestUrl: '/tests/fixtures/extensions/returnsModule/index.ts',
mode: 'page',
pageCode: 'returns',
})
Expand Down Expand Up @@ -119,8 +133,15 @@ import { expect, test } from '@playwright/test'

test('loads returns page extension', async ({ page }) => {
await page.goto(
'/?manifestUrl='
+ encodeURIComponent('%extension-url%/extension/%extension-id%')
'/?descriptor='
+ encodeURIComponent(JSON.stringify({
code: 'returnsModule',
baseUrl: 'https://extension.test',
entrypoint: '/build/worker.js',
pages: ['returns'],
stylesheet: '/build/extension.css',
targets: [],
}))
+ '&mode=page'
+ '&pageCode=returns'
+ '&fixture=order-basic'
Expand All @@ -142,8 +163,15 @@ import {
await page.goto('/')

await launchSandboxExtension(page, {
descriptor: {
code: 'promoModule',
baseUrl: 'https://extension.test',
entrypoint: '/build/worker.js',
pages: [],
stylesheet: null,
targets: ['order/card:common.after'],
},
fixture: 'order-basic',
manifestUrl: '%extension-url%/extension/%extension-id%',
mode: 'widget',
targets: ['order/card:common.after'],
})
Expand Down
Loading