-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Basic setup for chat-widget-adapters e2e tests
- Loading branch information
1 parent
5b13068
commit 6b7ffa1
Showing
16 changed files
with
24,973 additions
and
20,750 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"extends": [ | ||
"plugin:playwright/playwright-test" | ||
], | ||
"rules": { | ||
"@typescript-eslint/no-empty-function": "off", | ||
"@typescript-eslint/no-explicit-any": "off", | ||
"@typescript-eslint/no-var-requires": "off", | ||
"@typescript-eslint/no-unnecessary-type-assertion": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { ElementHandle, Frame, Locator, Page } from '@playwright/test' | ||
import { ChatData, WidgetState } from '@livechat/widget-core' | ||
import { matchFrame } from './utils' | ||
|
||
export const MAP_FRAMEWORK_TO_PORT = { | ||
React: '3001', | ||
Vue: '3002', | ||
Angular: '3003', | ||
} as const | ||
|
||
export class ExamplePage { | ||
readonly widgetIframeId: string = '#chat-widget' | ||
readonly widgetReadiness: Locator | ||
readonly dataContainers: { | ||
chatData: Locator | ||
customerData: Locator | ||
widgetIsReady: Locator | ||
widgetState: Locator | ||
} | ||
preChat: { | ||
emailInput: ElementHandle<SVGElement | HTMLElement> | ||
nameInput: ElementHandle<SVGElement | HTMLElement> | ||
} | ||
sentFrames: string[] = [] | ||
receivedFrames: string[] = [] | ||
serverCustomerId: null | string = null | ||
serverChat: null | ChatData = null | ||
widgetFrame: Frame | ||
widgetState: WidgetState | ||
|
||
constructor(private page: Page, private framework: keyof typeof MAP_FRAMEWORK_TO_PORT) { | ||
this.dataContainers = { | ||
chatData: page.locator('#chat-data'), | ||
customerData: page.locator('#customer-data'), | ||
widgetIsReady: page.locator('#widget-readiness'), | ||
widgetState: page.locator('#widget-state'), | ||
} | ||
} | ||
|
||
async goto() { | ||
this.page.on('websocket', (ws) => { | ||
ws.on('framesent', (event) => this.sentFrames.push(event.payload as string)) | ||
ws.on('framereceived', (event) => this.receivedFrames.push(event.payload as string)) | ||
}) | ||
|
||
await this.page.goto(`http://localhost:${MAP_FRAMEWORK_TO_PORT[this.framework]}`) | ||
await this.page.waitForSelector(`text=Hello ${this.framework}!`, { state: 'visible' }) | ||
} | ||
|
||
async getWidgetIframe() { | ||
await this.page.waitForSelector(this.widgetIframeId) | ||
|
||
const elementHandle = await this.page.$(this.widgetIframeId) | ||
this.widgetFrame = await elementHandle.contentFrame() | ||
} | ||
|
||
async startTheChat() { | ||
const startTheChatButton = await this.widgetFrame.waitForSelector('text=Start the chat', { | ||
state: 'visible', | ||
}) | ||
|
||
await startTheChatButton.click() | ||
|
||
await this.widgetFrame.waitForSelector('text=Hello. How may I help you?', { | ||
state: 'visible', | ||
}) | ||
|
||
const serverChat = matchFrame(this.receivedFrames, new RegExp(/incoming_chat/)).payload.chat | ||
this.serverChat = { | ||
chatId: serverChat.id, | ||
threadId: serverChat.thread.id, | ||
} | ||
} | ||
|
||
async minimizeWidget() { | ||
await this.widgetFrame.locator('[aria-label="Minimize window"]').click() | ||
} | ||
|
||
getPreChatFields() { | ||
return { | ||
emailInput: this.widgetFrame.locator('#email'), | ||
nameInput: this.widgetFrame.locator('#name'), | ||
} | ||
} | ||
|
||
getServerCustomerId() { | ||
return matchFrame(this.receivedFrames, new RegExp(/login/)).payload.customer_id | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { expect, test } from '@playwright/test' | ||
import { CustomerData, ChatData, WidgetState } from '@livechat/widget-core' | ||
import { ExamplePage, MAP_FRAMEWORK_TO_PORT } from './example-page' | ||
import { stringify } from './utils' | ||
|
||
test.describe.parallel('Example applications', () => { | ||
Object.keys(MAP_FRAMEWORK_TO_PORT).forEach((framework: keyof typeof MAP_FRAMEWORK_TO_PORT) => { | ||
test(`${framework} should render Chat Widget with provided data and update state accordingly`, async ({ page }) => { | ||
const customerData: CustomerData = { | ||
name: 'John Doe', | ||
email: 'john.doe@example.com', | ||
isReturning: false, | ||
sessionVariables: {}, | ||
id: null, | ||
status: 'browsing', | ||
} | ||
|
||
const widgetState: WidgetState = { | ||
availability: 'online', | ||
visibility: 'maximized', | ||
} | ||
|
||
let chatData: ChatData = null | ||
|
||
const examplePage = new ExamplePage(page, framework) | ||
await examplePage.goto() | ||
await examplePage.getWidgetIframe() | ||
|
||
customerData.id = examplePage.getServerCustomerId() | ||
await expect(examplePage.dataContainers.widgetIsReady).toHaveText('Widget is ready: true') | ||
await expect(examplePage.dataContainers.widgetState).toHaveText(`Widget state: ${stringify(widgetState)}`) | ||
await expect(examplePage.dataContainers.customerData).toHaveText(`Customer data: ${stringify(customerData)}`) | ||
await expect(examplePage.dataContainers.chatData).toHaveText(`Chat data: ${stringify(chatData)}`) | ||
|
||
const preChatFields = examplePage.getPreChatFields() | ||
await expect(preChatFields.emailInput).toHaveValue(customerData.email) | ||
await expect(preChatFields.nameInput).toHaveValue(customerData.name) | ||
|
||
await examplePage.startTheChat() | ||
customerData.status = 'chatting' | ||
chatData = examplePage.serverChat | ||
await expect(examplePage.dataContainers.chatData).toHaveText(`Chat data: ${stringify(chatData)}`) | ||
await expect(examplePage.dataContainers.customerData).toHaveText(`Customer data: ${stringify(customerData)}`) | ||
|
||
await examplePage.minimizeWidget() | ||
widgetState.visibility = 'minimized' | ||
await expect(examplePage.dataContainers.widgetState).toHaveText(`Widget state: ${stringify(widgetState)}`) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { PlaywrightTestConfig, devices } from '@playwright/test' | ||
|
||
const config: PlaywrightTestConfig = { | ||
testDir: '.', | ||
forbidOnly: !!process.env.CI, | ||
retries: process.env.CI ? 2 : 0, | ||
use: { | ||
trace: 'on-first-retry', | ||
}, | ||
webServer: { | ||
command: 'npm start examples', | ||
port: 3003, | ||
timeout: 120 * 1000, | ||
reuseExistingServer: !process.env.CI, | ||
}, | ||
projects: [ | ||
{ | ||
name: 'chromium', | ||
use: { ...devices['Desktop Chrome'] }, | ||
}, | ||
], | ||
} | ||
export default config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export function stringify(value: Parameters<typeof JSON.stringify>['0']) { | ||
return JSON.stringify(value, null, 2) | ||
} | ||
|
||
export function matchFrame(arr: string[], matcher: RegExp): Record<any, any> { | ||
return JSON.parse(arr.find((element) => element.match(matcher))) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.