Skip to content

Commit b5afd66

Browse files
committedApr 11, 2016
Create an Integration Test for the default Gatsby Wrappers
* Add `npm run setup` to setup symlinks for the test suite. * Add a note about `npm run setup` in CONTRIBUTING * Add `npm run test-integration` to run the slower tests.
1 parent 2a696e0 commit b5afd66

File tree

15 files changed

+192
-13
lines changed

15 files changed

+192
-13
lines changed
 

‎.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@ examples/blog/public/
3030
*.un~
3131
dist
3232
bin/published.js
33+
34+
# Build Path of Test Fixtures
35+
test/**/public

‎.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ addons:
3535
# script needed to test, because defaults don't work on osx
3636
script:
3737
- npm install
38+
- npm run setup
3839
- npm run test

‎CONTRIBUTING.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ simple steps:
1212

1313
* Clone the repo, navigate to its directory.
1414
* Execute `npm install` to install packages.
15+
* Execute `npm run setup` to set up the test suite.
1516
* Execute `npm uninstall -g gatsby && npm link`
1617
* Use `git pull` to update to latest Gatsby.
1718

‎lib/isomorphic/wrappers/html.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ import React, { PropTypes } from 'react'
22

33
module.exports = React.createClass({
44
propTypes: {
5-
page: PropTypes.shape({
6-
data: PropTypes.shape({
7-
body: PropTypes.string.isRequired,
5+
route: PropTypes.shape({
6+
page: PropTypes.shape({
7+
data: PropTypes.shape({
8+
body: PropTypes.string.isRequired,
9+
}),
810
}),
911
}),
1012
},
1113

1214
render () {
13-
const html = this.props.page.data.body
15+
const html = this.props.route.page.data.body
1416
return (
1517
<div dangerouslySetInnerHTML={{ __html: html }} />
1618
)

‎lib/isomorphic/wrappers/md.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import React, { PropTypes } from 'react'
22

3-
export default React.createClass({
3+
module.exports = React.createClass({
44
propTypes: {
5-
page: PropTypes.shape({
6-
data: PropTypes.shape({
7-
body: PropTypes.string.isRequired,
5+
route: PropTypes.shape({
6+
page: PropTypes.shape({
7+
data: PropTypes.shape({
8+
body: PropTypes.string.isRequired,
9+
}),
810
}),
911
}),
1012
},
1113

1214
render () {
13-
const post = this.props.page.data
15+
const post = this.props.route.page.data
1416
return (
1517
<div className="markdown">
1618
<h1>{post.title}</h1>

‎package.json

+8-4
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,12 @@
8484
"babel-cli": "^6.7.5",
8585
"babel-eslint": "^6.0.2",
8686
"babel-register": "^6.7.2",
87+
"bluebird": "^3.3.4",
8788
"eslint": "^2.7.0",
8889
"eslint-config-airbnb": "^6.1.0",
8990
"eslint-plugin-ava": "^2.0.1",
90-
"eslint-plugin-react": "^4.3.0"
91+
"eslint-plugin-react": "^4.3.0",
92+
"jsdom": "^8.3.0"
9193
},
9294
"engines": {
9395
"node": ">0.12.0"
@@ -110,9 +112,11 @@
110112
},
111113
"scripts": {
112114
"build": "babel lib --out-dir dist/",
113-
"lint": "eslint --ext .js,.jsx --ignore-pattern dist .",
114-
"test": "npm run lint && npm run test-node",
115-
"test-node": "node_modules/.bin/ava",
115+
"lint": "eslint --ext .js,.jsx --ignore-pattern dist --ignore-pattern public .",
116+
"test": "npm run lint && npm run test-node && npm run test-integration",
117+
"test-integration": "npm run build && node_modules/.bin/ava test/integration",
118+
"test-node": "node_modules/.bin/ava test/utils",
119+
"setup": "npm run build && scripts/setup.sh",
116120
"watch": "babel -w lib --out-dir dist/"
117121
},
118122
"ava": {

‎scripts/setup.sh

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env node
2+
3+
var path = require('path')
4+
var fs = require('fs-extra')
5+
var Promise = require('bluebird')
6+
7+
var mkdir = Promise.promisify(fs.mkdir)
8+
var symlink = Promise.promisify(fs.symlink)
9+
var readdir = Promise.promisify(fs.readdir)
10+
var remove = Promise.promisify(fs.remove)
11+
12+
var nodeModulesDirectory = path.join(process.cwd(), 'node_modules')
13+
var gatsbyDirectory = path.join(nodeModulesDirectory, 'gatsby')
14+
var fixturesDirectory = path.join(process.cwd(), 'test', 'fixtures')
15+
16+
function linkNodeModules (directory) {
17+
var fixtureNodeModules = path.join(fixturesDirectory, directory, 'node_modules')
18+
19+
return remove(fixtureNodeModules)
20+
.then(() => symlink(nodeModulesDirectory, fixtureNodeModules))
21+
}
22+
23+
function linkGatsby () {
24+
var gatsbyPackagePath = path.join(process.cwd(), 'package.json')
25+
var gatsbyDistPath = path.join(process.cwd(), 'dist')
26+
var fixturePackagePath = path.join(gatsbyDirectory, 'package.json')
27+
var fixtureDistPath = path.join(gatsbyDirectory, 'dist')
28+
29+
return remove(gatsbyDirectory)
30+
.then(() => mkdir(gatsbyDirectory))
31+
.then(() => {
32+
return Promise.all([
33+
symlink(gatsbyPackagePath, fixturePackagePath),
34+
symlink(gatsbyDistPath, fixtureDistPath)
35+
])
36+
})
37+
}
38+
39+
linkGatsby()
40+
.then(() => readdir(fixturesDirectory))
41+
.then(fixtures => fixtures.map(linkNodeModules))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict';
2+
3+
// This file is auto-written and used by Gatsby to require
4+
// files from your pages directory.
5+
module.exports = function (callback) {
6+
var context = require.context('./pages', true);
7+
if (module.hot) {
8+
module.hot.accept(context.id, function () {
9+
context = require.context('./pages', true);
10+
return callback(context);
11+
});
12+
}
13+
return callback(context);
14+
};

‎test/fixtures/starter-wrappers/config.toml

Whitespace-only changes.
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from 'react'
2+
import { prefixLink } from 'gatsby-helpers'
3+
4+
module.exports = React.createClass({
5+
displayName: 'HTML',
6+
propTypes: {
7+
body: React.PropTypes.string,
8+
},
9+
render () {
10+
const { body } = this.props
11+
12+
return (
13+
<html lang="en">
14+
<head>
15+
<meta charSet="utf-8" />
16+
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
17+
<meta
18+
name="viewport"
19+
content="width=device-width, initial-scale=1.0 maximum-scale=5.0"
20+
/>
21+
</head>
22+
<body className="landing-page">
23+
<div id="react-mount" dangerouslySetInnerHTML={{ __html: body }} />
24+
<script src={prefixLink('/bundle.js')} />
25+
</body>
26+
</html>
27+
)
28+
},
29+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react'
2+
3+
export default class Template extends React.Component {
4+
static get propTypes () {
5+
return { children: React.PropTypes.any }
6+
}
7+
8+
render () {
9+
return (
10+
<main>
11+
{this.props.children}
12+
</main>
13+
)
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<h1>html</h1>
2+
<p>This is a page with the .html extension.</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
---
3+
# md
4+
5+
This is a page with the .md extension.
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import test from 'ava'
2+
import path from 'path'
3+
import Promise from 'bluebird'
4+
import fsExtra from 'fs-extra'
5+
import { exec, jsdom } from '../support'
6+
const fs = Promise.promisifyAll(fsExtra)
7+
8+
const starterPath = path.resolve('../', 'fixtures', 'starter-wrappers')
9+
const buildPath = path.join(starterPath, 'public')
10+
11+
test.serial('can build the starter', async t => {
12+
await fs.remove(buildPath)
13+
14+
const exitCode = await exec('gatsby', ['build'], { cwd: starterPath })
15+
const bundle = await fs.statAsync(path.join(buildPath, 'bundle.js'))
16+
17+
t.is(exitCode, 0)
18+
t.truthy(bundle)
19+
})
20+
21+
test('html/index.html has an h1 that states file extention', async t => {
22+
const { document } = await jsdom(path.join(buildPath, 'html/index.html'))
23+
t.truthy(document)
24+
25+
const heading = document.querySelector('h1')
26+
t.truthy(heading)
27+
28+
const headingText = heading.textContent
29+
t.is(headingText, 'html')
30+
})
31+
32+
test('md/index.html has an h1 that states file extention', async t => {
33+
const { document } = await jsdom(path.join(buildPath, 'md/index.html'))
34+
t.truthy(document)
35+
36+
// MD wrapper spits out an h1 tag. Shouldn't it be consistent with HTML
37+
const heading = document.querySelectorAll('h1')[1]
38+
t.truthy(heading)
39+
40+
const headingText = heading.textContent
41+
t.is(headingText, 'md')
42+
})

‎test/support.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import jsdomlib from 'jsdom'
2+
import Promise from 'bluebird'
3+
import { spawn } from 'child_process'
4+
5+
export function exec (command, args, options) {
6+
return new Promise((resolve, reject) => {
7+
const child = spawn(command, args, options)
8+
child.on('exit', code => resolve(code))
9+
child.on('error', error => reject(error))
10+
child.stdout.on('data', data => { console.log(data.toString()) })
11+
child.stderr.on('data', data => { console.error(data.toString()) })
12+
})
13+
}
14+
15+
export function jsdom (html) {
16+
const env = Promise.promisify(jsdomlib.env)
17+
return env(html)
18+
}

0 commit comments

Comments
 (0)
Please sign in to comment.