diff --git a/package.json b/package.json
index 84319855..1255822b 100644
--- a/package.json
+++ b/package.json
@@ -10,10 +10,11 @@
"build": "webpack --config webpack.config.prop.js && npm run build:types",
"build:types": "node -e \"require('fs-extra').removeSync('lib')\" && tsc -p tsconfig.build.json",
"build:ssr": "npm --prefix ssr-test ci --ignore-scripts && npm --prefix ssr-test run build",
+ "check:ssr-hydration": "node scripts/check-ssr-hydration.js",
"check:package-export": "node scripts/check-package-export.js",
"build:analyze": "ANALYZE=true webpack --config webpack.config.prop.js",
"doc": "webpack --config webpack.config.doc.js",
- "verify": "npm test -- --runInBand && npm run lint && npm run build && npm run check:package-export && npm run doc && npm run build:ssr && npm pack --dry-run",
+ "verify": "npm test -- --runInBand && npm run lint && npm run build && npm run check:package-export && npm run doc && npm run build:ssr && npm run check:ssr-hydration && npm pack --dry-run",
"pub": "npm publish",
"prepublishOnly": "npm run build",
"predeploy": "npm run doc",
diff --git a/scripts/check-ssr-hydration.js b/scripts/check-ssr-hydration.js
new file mode 100644
index 00000000..0959020b
--- /dev/null
+++ b/scripts/check-ssr-hydration.js
@@ -0,0 +1,47 @@
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+const { JSDOM } = require('jsdom');
+
+const serverMarkup = [
+ '
',
+ '',
+ '',
+].join('');
+const dom = new JSDOM(serverMarkup, {
+ runScripts: 'outside-only',
+ url: 'http://127.0.0.1:8005/',
+});
+
+async function verifyHydration() {
+ dom.window.requestAnimationFrame = callback => dom.window.setTimeout(callback, 0);
+ dom.window.cancelAnimationFrame = id => dom.window.clearTimeout(id);
+
+ const bundlePath = path.join(__dirname, '..', 'ssr-test', 'client-dist', 'main.js');
+ dom.window.eval(fs.readFileSync(bundlePath, 'utf8'));
+
+ const openButton = dom.window.document.querySelector('#root button');
+ assert(openButton, 'The SSR fixture must preserve its server-rendered button during hydration');
+ assert.strictEqual(openButton.textContent, 'open');
+
+ openButton.dispatchEvent(new dom.window.MouseEvent('click', { bubbles: true }));
+ await new Promise(resolve => dom.window.setTimeout(resolve, 50));
+
+ assert.strictEqual(openButton.textContent, 'close', 'The hydrated fixture must respond to user input');
+ assert(
+ dom.window.document.querySelector('[aria-label="Close viewer"]'),
+ 'The hydrated fixture must render the Viewer component'
+ );
+
+ console.log('SSR fixture hydrated and opened the Viewer component.');
+}
+
+verifyHydration()
+ .then(() => {
+ dom.window.close();
+ })
+ .catch(error => {
+ dom.window.close();
+ console.error(error);
+ process.exit(1);
+ });
diff --git a/ssr-test/app.js b/ssr-test/app.js
index 37b8a5db..93d0d5e8 100644
--- a/ssr-test/app.js
+++ b/ssr-test/app.js
@@ -1,7 +1,7 @@
const React = require('react');
const Viewer = typeof window === 'undefined'
? () => null
- : require('../dist/index').default;
+ : require('../dist/index');
function App () {
const [ visible, setVisible ] = React.useState(false);