diff --git a/.circleci/config.yml b/.circleci/config.yml
index 817aa5569..c38b41685 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -8,7 +8,7 @@ references:
container_config_node: &container_config_node
working_directory: ~/project/build
docker:
- - image: circleci/node:12
+ - image: circleci/node:12-browsers
workspace_root: &workspace_root
~/project
@@ -105,6 +105,14 @@ jobs:
- run:
name: Run storybook
command: npm run start-storybook:ci
+
+ e2e-test:
+ <<: *container_config_node
+ steps:
+ - *attach_workspace
+ - run:
+ name: Run end to end test
+ command: npm run e2e
publish:
<<: *container_config_node
@@ -164,6 +172,9 @@ workflows:
- test:
requires:
- build
+ - e2e-test:
+ requires:
+ - build
- deploy:
filters:
<<: *filters_only_main
diff --git a/.eslintignore b/.eslintignore
index 114afbe73..0fe84d9ab 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -8,3 +8,4 @@
**/public-prod/**
**/blueprints/**
web/static/**
+/e2e/**
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index c0be6db50..78ec717b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@ bower_components
npm-debug.log
.DS_Store
dist
-.idea
\ No newline at end of file
+.idea
+coverage
\ No newline at end of file
diff --git a/components/x-interaction/readme.md b/components/x-interaction/readme.md
index 9c7f805f2..b7c614c7a 100644
--- a/components/x-interaction/readme.md
+++ b/components/x-interaction/readme.md
@@ -179,7 +179,7 @@ When rendered on the server side, components output an extra wrapper element, wi
`x-interaction` exports a function `hydrate`. This should be called on the client side. It inspects the global serialisation data on the page, uses the identifiers to find the wrapper elements, and calls `render` from your chosen `x-engine` client-side runtime to render component instances into the wrappers.
-Before calling `hydrate`, you must first `import` any `x-interaction` components that will be rendered on the page. The components register themselves with the `x-interaction` runtime when imported; you don't need to do anything with the imported component. This will also ensure the component is included in your client-side bundle.
+Before calling `hydrate`, you must first `import` any `x-interaction` components that will be rendered on the page. The components register themselves with the `x-interaction` runtime when imported; you don't need to do anything with the imported component. This will also ensure the component is included in your client-side bundle. Similarly if the component that you're server side rendering is just a component that you've created through `withActions`, make sure you import that component along with its registerComponent invokation.
Because `hydrate` expects the wrappers to be present in the DOM when called, it should be called after [`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded). Depending on your page structure, it might be appropriate to hydrate the component when it's scrolled into view.
diff --git a/e2e/app.js b/e2e/app.js
new file mode 100644
index 000000000..28e873a04
--- /dev/null
+++ b/e2e/app.js
@@ -0,0 +1,5 @@
+// set up app to host main.js file included in server side rendered html
+const express = require('express')
+const server = express()
+server.use(express.static(__dirname))
+exports.app = server
diff --git a/e2e/common.js b/e2e/common.js
new file mode 100644
index 000000000..d2af05a15
--- /dev/null
+++ b/e2e/common.js
@@ -0,0 +1,21 @@
+const { withActions, registerComponent } = require('@financial-times/x-interaction')
+const { h } = require('@financial-times/x-engine')
+
+export const greetingActions = withActions({
+ actionOne() {
+ return { greeting: 'world' }
+ }
+})
+
+export const GreetingComponent = greetingActions(({ greeting, actions }) => {
+ return (
+