Description
Following the below guide migrate tests located in folder:
__tests__/html/fluentTheme/customElement
Migrating BotFramework-WebChat Tests from html to html2
This guide covers the migration process from the legacy __tests__/html
test structure to the modern __tests__/html2
structure, based on the simplified migration patterns established in the BotFramework-WebChat project.
Overview
The migration involves updating test files to use:
- ES Modules (ESM) instead of Babel transpilation
- CDN dependencies for React instead of bundled assets
- Global
renderWebChat
function where possible for consistent rendering - Theme and variant query parameters where appropriate for consistent theming
Migration Steps
1. File Structure and Organization
Creating Test Directories
# Create the html2 directory structure or check existance
mkdir -p __tests__/html2/[feature-name]/
File Naming Convention
- Main test file:
[testName].html
- Theme/variant files:
[testName].[theme].[variant].html
(redirect files) - Examples:
typingIndicator.scroll.fluent.copilot.html
layout.fluent.html
2. HTML Document Structure Migration
Before (Legacy Structure)
<!DOCTYPE html>
<html lang="en-US">
<head>
<script crossorigin="anonymous" src="https://unpkg.com/@babel/standalone@7.8.7/babel.min.js"></script>
<script crossorigin="anonymous" src="https://unpkg.com/react@16.8.6/umd/react.development.js"></script>
<script crossorigin="anonymous" src="https://unpkg.com/react-dom@16.8.6/umd/react-dom.development.js"></script>
<!-- More UMD scripts -->
</head>
After (Modern Structure)
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18.3.1",
"react-dom": "https://esm.sh/react-dom@18.3.1",
"react-dom/": "https://esm.sh/react-dom@18.3.1/"
}
}
</script>
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script type="module">
import React from 'react';
window.React = React;
</script>
<script defer crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
<script defer crossorigin="anonymous" src="/__dist__/botframework-webchat-fluent-theme.production.min.js"></script>
</head>
3. Dependency Management
Remove These Dependencies
@babel/standalone
Keep These Dependencies
<!-- Test infrastructure -->
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<!-- defer WebChat bundles to wait for React availability -->
<script defer crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
<script defer crossorigin="anonymous" src="/__dist__/botframework-webchat-fluent-theme.production.min.js"></script>
Optional ES Module Imports
<!-- Add more into import map if needed for specific test dependencies -->
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18.3.1",
"react-dom": "https://esm.sh/react-dom@18.3.1",
"react-dom/": "https://esm.sh/react-dom@18.3.1/",
"@testduet/wait-for": "https://unpkg.com/@testduet/wait-for@main/dist/wait-for.mjs",
"jest-mock": "https://esm.sh/jest-mock"
}
}
</script>
4. Using the Global renderWebChat
Function
Where appropriate use the globaly available renderWebChat function which respects query parameters
Basic Usage
// The renderWebChat function is globally available
run(async function () {
const { directLine, store } = testHelpers.createDirectLineEmulator();
// Simple rendering - theme and variant handled automatically via query params
renderWebChat(
{ directLine, store },
document.getElementById('webchat')
);
await pageConditions.uiConnected();
// Test logic...
await host.snapshot('local');
});
With Additional Props
run(async function () {
const { directLine, store } = testHelpers.createDirectLineEmulator();
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
features: [{ name: 'prefers-reduced-motion', value: 'reduce' }]
});
renderWebChat(
{
directLine,
store,
styleOptions: {
botAvatarBackgroundColor: '#304E7A',
// other style options
}
},
document.getElementById('webchat')
);
await pageConditions.uiConnected();
// Test continues...
});
5. Theme and Variant Redirect Files
Create simple redirect files for different theme/variant combinations.
It works only with the global renderWebChat
function. If you can't use it, handle query paramters explicitly in the test file.
Example: Fluent Copilot Theme
<!-- typingIndicator.scroll.fluent.copilot.html -->
<!doctype html>
<html>
<head>
<script>
location = './typingIndicator.scroll?theme=fluent&variant=copilot';
</script>
</head>
<body></body>
</html>
Supported Query Parameters
theme=fluent
- Enables Fluent themevariant=copilot
- Enables Copilot variant (requires Fluent theme)
6. ES Module Script Structure
Modern Script Section
<script type="module">
// Import ES modules if needed
import { waitFor } from '@testduet/wait-for';
// Access query parameters
const isLivestream = new URL(location).searchParams.has('livestream');
run(async function () {
// Test logic using global renderWebChat function
const { directLine, store } = testHelpers.createDirectLineEmulator();
renderWebChat(
{ directLine, store },
document.getElementById('webchat')
);
await pageConditions.uiConnected();
// Continue with test...
});
</script>
7. Removed Complexity
No More JSX to React.createElement Conversion
// ❌ OLD: Manual createElement calls
React.createElement(
FluentProvider,
{ theme: fluentTheme },
React.createElement(FluentThemeProvider, ...)
);
// ✅ NEW: Handled by either global renderWebChat
renderWebChat({ directLine, store }, container);
Common Migration Patterns
1. Simple Feature Test Migration
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18.3.1",
"react-dom": "https://esm.sh/react-dom@18.3.1",
"react-dom/": "https://esm.sh/react-dom@18.3.1/"
}
}
</script>
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script type="module">
import React from 'react';
window.React = React;
</script>
<script defer crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
<script defer crossorigin="anonymous" src="/__dist__/botframework-webchat-fluent-theme.production.min.js"></script>
</head>
<body>
<main id="webchat"></main>
<script type="module">
run(async function () {
const { directLine, store } = testHelpers.createDirectLineEmulator();
renderWebChat(
{ directLine, store },
document.getElementById('webchat')
);
await pageConditions.uiConnected();
// Test logic...
await host.snapshot('local');
});
</script>
</body>
</html>
2. Feature Test with ES Module Dependencies
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18.3.1",
"react-dom": "https://esm.sh/react-dom@18.3.1",
"react-dom/": "https://esm.sh/react-dom@18.3.1/",
"@testduet/wait-for": "https://unpkg.com/@testduet/wait-for@main/dist/wait-for.mjs"
}
}
</script>
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script type="module">
import React from 'react';
window.React = React;
</script>
<script defer crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
<script defer crossorigin="anonymous" src="/__dist__/botframework-webchat-fluent-theme.production.min.js"></script>
</head>
<body>
<main id="webchat"></main>
<script type="module">
import { waitFor } from '@testduet/wait-for';
run(async function () {
const { directLine, store } = testHelpers.createDirectLineEmulator();
renderWebChat(
{ directLine, store },
document.getElementById('webchat')
);
await pageConditions.uiConnected();
// Use imported modules
await waitFor(() => expect(someCondition()).toBeTruthy());
await host.snapshot('local');
});
</script>
</body>
</html>
3. Feature Test with Custom Styling
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18.3.1",
"react-dom": "https://esm.sh/react-dom@18.3.1",
"react-dom/": "https://esm.sh/react-dom@18.3.1/",
"@testduet/wait-for": "https://unpkg.com/@testduet/wait-for@main/dist/wait-for.mjs"
}
}
</script>
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script type="module">
import React from 'react';
window.React = React;
</script>
<script defer crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
<script defer crossorigin="anonymous" src="/__dist__/botframework-webchat-fluent-theme.production.min.js"></script>
<style>
#webchat .webchat__typing-indicator {
background-image: url(data:image/gif;base64,/* custom styling */);
background-color: black;
}
</style>
</head>
<body>
<main id="webchat"></main>
<script type="module">
run(async function () {
await host.sendDevToolsCommand('Emulation.setEmulatedMedia', {
features: [{ name: 'prefers-reduced-motion', value: 'reduce' }]
});
const { directLine, store } = testHelpers.createDirectLineEmulator();
renderWebChat(
{ directLine, store },
document.getElementById('webchat')
);
await pageConditions.uiConnected();
// Test continues...
});
</script>
</body>
</html>
Migration Checklist
Before Migration
- Identify the test's purpose and required dependencies
- Note any special styling or configuration requirements
- Check for Babel usage that needs removal
- Identify theme/variant requirements by looking into similar test files test-file-name.*
During Migration
- Create new directory structure in
__tests__/html2
- Replace Babel with ES module script (if needed)
- Replace manual rendering with
renderWebChat()
calls if possible - Update snapshot calls to use 'local'
- Create theme/variant redirect files if needed
After Migration
- Test default rendering
- Test theme/variant combinations via redirects
- Verify all test functionality works
- Check that snapshots are generated correctly
- Ensure any ES module dependencies load correctly
Query Parameter Reference
The renderWebChat
global function automatically handles these query parameters:
Parameter | Values | Description |
---|---|---|
theme |
fluent |
Enables Fluent theme rendering |
variant |
copilot |
Enables Copilot variant (requires theme=fluent ) |
Example URLs
- Default:
test
assuming filename istest.html
- Fluent theme:
test?theme=fluent
- Copilot variant:
test?theme=fluent&variant=copilot
- custom:
test?custom=optional-value
for custom test cases (handled explicitly in the test file)
Troubleshooting
Common Issues
-
renderWebChat not defined
- Ensure
/test-page-object.js
is loaded
- Ensure
-
Theme not applying
- Verify query parameters are correct
- Ensure fluent-theme bundle is loaded
-
ES module import errors
- Check importmap syntax and URLs
- Verify ESM dependencies are actually needed