Skip to content

Commit

Permalink
feat: embedded chat mode - lazy style attachment (DX-996) (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
DecathectZero committed Feb 22, 2024
1 parent 9a250ba commit 623a014
Show file tree
Hide file tree
Showing 59 changed files with 1,339 additions and 419 deletions.
28 changes: 27 additions & 1 deletion .circleci/continue-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ defaults:
template: basic_fail_1
branch_pattern: master

executors:
playwright:
docker:
- image: mcr.microsoft.com/playwright:v1.41.1-jammy

jobs:
test: # Main unit, style, and dependency tests
executor: vfcommon/node-executor-node-20
Expand All @@ -47,6 +52,20 @@ jobs:
## disable sonarcloud until project set up
# - sonarcloud/scan

e2e:
executor: playwright
steps:
- checkout
- attach_workspace:
at: ~/project
- vfcommon/install_node_modules:
avoid_post_install_scripts: false
- run:
working_directory: packages/react-chat
command: yarn test:e2e
- store_artifacts:
path: packages/react-chat/test-results

push-to-cdn: # Main unit, style, and dependency tests
executor: vfcommon/node-executor-node-20
steps: # a collection of executable commands
Expand Down Expand Up @@ -76,14 +95,20 @@ workflows:
- persist_to_workspace:
root: "."
paths:
- ./*/*/dist # persist dist folder too
- ./packages/*/dist # persist dist folder too

- test:
<<: *slack-fail-post-step
context: dev-test
requires:
- build

- e2e:
<<: *slack-fail-post-step
context: dev-test
requires:
- build

- vfcommon/monorepo_release:
<<: *slack-fail-post-step
executor: vfcommon/node-executor-node-20
Expand All @@ -94,6 +119,7 @@ workflows:
commit_message: "chore(release): publish --skip-ci"
requires:
- test
- e2e
filters:
branches:
only: master
Expand Down
11 changes: 9 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@
"eslint.runtime": "node",
"eslint.execArgv": ["--max_old_space_size=8192"],
"eslint.options": {
"extensions": [".js", ".jsx", ".md", ".mdx", ".ts", ".tsx"]
"extensions": [
".js",
".jsx",
".md",
".mdx",
".ts",
".tsx"
]
},
"eslint.validate": [
"markdown",
Expand All @@ -18,4 +25,4 @@
"typescript",
"typescriptreact"
]
}
}
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
"fixpack": "^4.0.0",
"husky": "7.0.0",
"lint-staged": ">=10",
"turbo": "1.5.5"
"npm-run-all": "4.1.5",
"turbo": "1.5.5",
"typescript": "4.8.4"
},
"engines": {
"node": ">=12"
Expand All @@ -45,7 +47,10 @@
"prepare": "husky install",
"setup_github_pages": "./scripts/setup_github_pages.sh",
"test:dependencies": "depcheck && turbo run test:dependencies",
"test:unit": "turbo run test:unit"
"test:unit": "turbo run test:unit",
"//": "Scripts to make binaries available to workspaces",
"g:run-p": "cd $INIT_CWD && run-p",
"g:tsc": "cd $INIT_CWD && tsc"
},
"volta": {
"node": "20.10.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/react-chat/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module.exports = {
},
overrides: [
{
files: ['test/**/*', 'config/**/*', '.storybook/**/*', '**/*.story.tsx', '**/*.test.*', '**/*.mdx', '*.config.ts'],
files: ['test/**/*', 'e2e/**/*', 'config/**/*', '.storybook/**/*', '**/*.story.tsx', '**/*.test.*', '**/*.mdx', '*.config.ts'],
extends: ['@voiceflow/eslint-config/utility'],
rules: {
// off
Expand Down
5 changes: 5 additions & 0 deletions packages/react-chat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
41 changes: 41 additions & 0 deletions packages/react-chat/e2e/embedded.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>

<head>
<title>Embedded Mode</title>
<style>
body {
background-color: #f9f9f9;
}

#flat-chat {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>

<body>
<div id="flat-chat"></div>

<script type="text/javascript">
(function (d, t) {
var v = d.createElement(t), s = d.getElementsByTagName(t)[0];
v.onload = function () {
window.voiceflow.chat.load({
verify: { projectID: 'projectID' },
render: {
mode: 'embedded',
target: document.getElementById('flat-chat'),
},
});
}
v.src = "../dist/bundle.mjs"; v.type = "text/javascript"; s.parentNode.insertBefore(v, s);
})(document, 'script');
</script>
</body>

</html>
11 changes: 11 additions & 0 deletions packages/react-chat/e2e/embedded.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { expect, test } from '@playwright/test';

test('renders embedded webchat and starts automatically', async ({ page }) => {
await page.goto('embedded');

const chat = page.locator('.vfrc-chat');
await chat.waitFor({ state: 'visible' });
expect(chat).toBeInViewport();

await page.locator('.vfrc-chat-input').waitFor({ state: 'visible' });
});
28 changes: 28 additions & 0 deletions packages/react-chat/e2e/overlay.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>

<head>
<title>Overlay mode</title>
<style>
body {
background-color: #f9f9f9;
}
</style>
</head>

<body>
<script type="text/javascript">
(function (d, t) {
var v = d.createElement(t), s = d.getElementsByTagName(t)[0];
v.onload = function () {
window.voiceflow.chat.load({
verify: { projectID: 'projectID' },
render: { mode: 'overlay' }
});
}
v.src = "../dist/bundle.mjs"; v.type = "text/javascript"; s.parentNode.insertBefore(v, s);
})(document, 'script');
</script>
</body>

</html>
40 changes: 40 additions & 0 deletions packages/react-chat/e2e/overlay.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { expect, test } from '@playwright/test';

test('renders launcher and widget appears on click', async ({ page }) => {
await page.goto('overlay');

const launcher = page.locator('.vfrc-launcher');
await launcher.waitFor({ state: 'visible' });
await launcher.click();

await page.locator('.vfrc-chat').waitFor({ state: 'visible' });

page.locator('.vfrc-footer .vfrc-button').click();

await page.locator('.vfrc-chat-input').waitFor({ state: 'visible' });
});

test('control widget visibility and open state', async ({ page }) => {
await page.goto('overlay');

const launcher = page.locator('.vfrc-launcher');
const chat = page.locator('.vfrc-chat');

await launcher.waitFor({ state: 'visible' });

await page.evaluate(() => window.voiceflow?.chat?.open());

await chat.waitFor({ state: 'visible' });

await page.evaluate(() => window.voiceflow?.chat?.close());

expect(chat).not.toBeInViewport();

await page.evaluate(() => window.voiceflow?.chat?.hide());

await launcher.waitFor({ state: 'hidden' });

await page.evaluate(() => window.voiceflow?.chat?.show());

await launcher.waitFor({ state: 'visible' });
});
29 changes: 29 additions & 0 deletions packages/react-chat/e2e/proactive.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>

<head>
<title>Overlay mode - proactive messages</title>
<style>
body {
background-color: #f9f9f9;
}
</style>
</head>

<body>
<script type="text/javascript">
(function (d, t) {
var v = d.createElement(t), s = d.getElementsByTagName(t)[0];
v.onload = function () {
window.voiceflow.chat.load({
verify: { projectID: 'projectID' },
render: { mode: 'overlay' },
autostart: true
});
}
v.src = "../dist/bundle.mjs"; v.type = "text/javascript"; s.parentNode.insertBefore(v, s);
})(document, 'script');
</script>
</body>

</html>
21 changes: 21 additions & 0 deletions packages/react-chat/e2e/proactive.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test } from '@playwright/test';
import { Trace } from '@voiceflow/base-types';

test('renders launcher and widget appears on click', async ({ page }) => {
const message = 'Welcome to our chat';

await page.goto('proactive');

await page.locator('.vfrc-launcher').waitFor({ state: 'visible' });

await page.evaluate(
([message]) =>
window.voiceflow?.chat?.proactive.push({
type: 'text' as Trace.TraceType.TEXT,
payload: { slate: { id: '', content: [] }, message },
}),
[message]
);

await page.waitForSelector(`text=${message}`);
});
15 changes: 15 additions & 0 deletions packages/react-chat/examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@
body {
background-color: #f9f9f9;
}
#flat-chat {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>

<body>
<div id="flat-chat"></div>
<div id="voiceflow-chat-frame"></div>

<script>
function _vf_load() {
window.voiceflow.chat.load({
Expand All @@ -20,6 +30,11 @@
user: {
name: 'Development User',
},
render: {
mode: 'embedded',
target: document.getElementById('flat-chat'),
},
autostart: true,
allowDangerousHTML: false,
});
}
Expand Down
12 changes: 9 additions & 3 deletions packages/react-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"@voiceflow/dtos": "1.10.0",
"@voiceflow/sdk-runtime": "1.7.0",
"@voiceflow/slate-serializer": "1.5.5",
"@voiceflow/stitches-react": "2.0.0",
"@voiceflow/stitches-react": "2.3.0",
"@voiceflow/voiceflow-types": "3.26.21",
"bowser": "^2.11.0",
"chroma-js": "2.4.2",
Expand All @@ -35,6 +35,7 @@
"devDependencies": {
"@babel/core": "^7.18.10",
"@emotion/core": "10.1.1",
"@playwright/test": "^1.41.2",
"@storybook/addon-actions": "^6.5.10",
"@storybook/addon-essentials": "^6.5.10",
"@storybook/addon-interactions": "^6.5.10",
Expand All @@ -46,6 +47,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "12.1.4",
"@types/chroma-js": "^2.1.4",
"@types/node": "^20.11.19",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.6",
"@vitejs/plugin-react": "^2.0.1",
Expand All @@ -60,6 +62,7 @@
"eslint-plugin-storybook": "^0.6.4",
"fixpack": "^4.0.0",
"happy-dom": "^6.0.4",
"http-server": "14.1.1",
"husky": "^8.0.0",
"lint-staged": "13.0.3",
"prettier": "2.7.1",
Expand Down Expand Up @@ -94,7 +97,7 @@
},
"prettier": "@voiceflow/prettier-config",
"scripts": {
"build": "yarn clean && yarn build:package && yarn build:bundle",
"build": "yarn clean && yarn g:run-p \"types\" \"build:package\" \"build:bundle\"",
"build:bundle": "NODE_ENV=production vite build",
"build:docs": "NODE_OPTIONS=--openssl-legacy-provider STORYBOOK_BASE_HREF=react-chat build-storybook -o docs",
"build:package": "NODE_ENV=production vite --config vite.package.config.ts build && tsc-alias -p tsconfig.build.json",
Expand All @@ -106,10 +109,13 @@
"lint:quiet": "yarn lint --quiet",
"lint:report": "yarn lint:output",
"prepublishOnly": "yarn build",
"start:e2e": "http-server -o e2e",
"storybook": "start-storybook -p 6006",
"test": "yarn test:run",
"test:dependencies": "depcheck",
"test:unit": "NODE_ENV=test vitest run --coverage"
"test:unit": "NODE_ENV=test vitest run --coverage",
"test:e2e": "yarn playwright test",
"types": "yarn g:tsc --project tsconfig.build.json --noEmit"
},
"types": "build/src/package.entry.d.ts"
}
Loading

0 comments on commit 623a014

Please sign in to comment.