mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-11 19:04:30 +00:00
Merge pull request #673 from mrkishi/testing-issue
Harden tests (...a bit)
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,11 +3,7 @@ yarn.lock
|
|||||||
yarn-error.log
|
yarn-error.log
|
||||||
node_modules
|
node_modules
|
||||||
cypress/screenshots
|
cypress/screenshots
|
||||||
test/app/.sapper
|
|
||||||
test/app/src/manifest
|
|
||||||
__sapper__
|
__sapper__
|
||||||
test/app/export
|
|
||||||
test/app/build
|
|
||||||
sapper
|
sapper
|
||||||
runtime.js
|
runtime.js
|
||||||
dist
|
dist
|
||||||
|
|||||||
@@ -1,49 +1,77 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import puppeteer from 'puppeteer';
|
import puppeteer from 'puppeteer';
|
||||||
import * as ports from 'port-authority';
|
|
||||||
import { fork, ChildProcess } from 'child_process';
|
import { fork, ChildProcess } from 'child_process';
|
||||||
|
import { AddressInfo } from 'net';
|
||||||
|
|
||||||
|
import { wait } from '../utils'
|
||||||
|
|
||||||
|
const DEFAULT_ENTRY = '__sapper__/build/server/server.js';
|
||||||
|
const DELAY = parseInt(process.env.SAPPER_TEST_DELAY) || 50;
|
||||||
|
|
||||||
declare const start: () => Promise<void>;
|
declare const start: () => Promise<void>;
|
||||||
declare const prefetchRoutes: () => Promise<void>;
|
declare const prefetchRoutes: () => Promise<void>;
|
||||||
declare const prefetch: (href: string) => Promise<void>;
|
declare const prefetch: (href: string) => Promise<void>;
|
||||||
declare const goto: (href: string) => Promise<void>;
|
declare const goto: (href: string) => Promise<void>;
|
||||||
|
|
||||||
type StartOpts = {
|
|
||||||
requestInterceptor?: (interceptedRequst: puppeteer.Request) => any
|
|
||||||
};
|
|
||||||
|
|
||||||
export class AppRunner {
|
export class AppRunner {
|
||||||
cwd: string;
|
exiting: boolean;
|
||||||
entry: string;
|
terminate: Promise<any>;
|
||||||
port: number;
|
|
||||||
proc: ChildProcess;
|
server: ChildProcess;
|
||||||
|
address: AddressInfo;
|
||||||
|
base: string;
|
||||||
messages: any[];
|
messages: any[];
|
||||||
|
errors: Error[];
|
||||||
|
|
||||||
browser: puppeteer.Browser;
|
browser: puppeteer.Browser;
|
||||||
page: puppeteer.Page;
|
page: puppeteer.Page;
|
||||||
|
|
||||||
constructor(cwd: string, entry: string) {
|
sapper = {
|
||||||
this.cwd = cwd;
|
start: () => this.page.evaluate(() => start()).then(() => void 0),
|
||||||
this.entry = path.join(cwd, entry);
|
prefetchRoutes: () => this.page.evaluate(() => prefetchRoutes()).then(() => void 0),
|
||||||
|
prefetch: (href: string) => this.page.evaluate((href: string) => prefetch(href), href).then(() => void 0),
|
||||||
|
goto: (href: string) => this.page.evaluate((href: string) => goto(href), href).then(() => void 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
this.messages = [];
|
this.messages = [];
|
||||||
|
this.errors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async start({ requestInterceptor }: StartOpts = {}) {
|
async start(cwd: string, entry: string = DEFAULT_ENTRY) {
|
||||||
this.port = await ports.find(3000);
|
const server_listening = deferred();
|
||||||
|
const server_closed = deferred();
|
||||||
|
const browser_closed = deferred();
|
||||||
|
|
||||||
this.proc = fork(this.entry, [], {
|
this.terminate = Promise.all([server_closed, browser_closed]);
|
||||||
cwd: this.cwd,
|
|
||||||
env: {
|
this.server = fork(path.join(cwd, entry), [], { cwd });
|
||||||
PORT: String(this.port)
|
this.server.on('exit', () => {
|
||||||
|
server_listening.reject();
|
||||||
|
server_closed.settle(this.exiting);
|
||||||
|
});
|
||||||
|
this.server.on('message', message => {
|
||||||
|
if (!message.__sapper__) return;
|
||||||
|
|
||||||
|
switch (message.event) {
|
||||||
|
case 'listening':
|
||||||
|
this.address = message.address;
|
||||||
|
this.base = `http://localhost:${this.address.port}`;
|
||||||
|
|
||||||
|
server_listening.resolve();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'error':
|
||||||
|
this.errors.push(Object.assign(new Error(), message.error));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.messages.push(message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.proc.on('message', message => {
|
|
||||||
if (!message.__sapper__) return;
|
|
||||||
this.messages.push(message);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.browser = await puppeteer.launch({ args: ['--no-sandbox'] });
|
this.browser = await puppeteer.launch({ args: ['--no-sandbox'] });
|
||||||
|
this.browser.on('disconnected', () => browser_closed.settle(this.exiting));
|
||||||
|
|
||||||
this.page = await this.browser.newPage();
|
this.page = await this.browser.newPage();
|
||||||
this.page.on('console', msg => {
|
this.page.on('console', msg => {
|
||||||
@@ -54,25 +82,28 @@ export class AppRunner {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (requestInterceptor) {
|
await server_listening;
|
||||||
await this.page.setRequestInterception(true);
|
|
||||||
this.page.on('request', requestInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return this;
|
||||||
page: this.page,
|
|
||||||
base: `http://localhost:${this.port}`,
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
start: () => this.page.evaluate(() => start()).then(() => void 0),
|
|
||||||
prefetchRoutes: () => this.page.evaluate(() => prefetchRoutes()).then(() => void 0),
|
|
||||||
prefetch: (href: string) => this.page.evaluate((href: string) => prefetch(href), href).then(() => void 0),
|
|
||||||
goto: (href: string) => this.page.evaluate((href: string) => goto(href), href).then(() => void 0),
|
|
||||||
title: () => this.page.$eval('h1', node => node.textContent).then(serializable => String(serializable))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
capture(fn: () => any): Promise<string[]> {
|
load(url: string) {
|
||||||
|
if (url[0] === '/') {
|
||||||
|
url = `${this.base}${url}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.page.goto(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
text(selector: string) {
|
||||||
|
return this.page.$eval(selector, node => node.textContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
wait(extra_ms: number = 0) {
|
||||||
|
return wait(DELAY + extra_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
capture_requests(fn: () => any): Promise<string[]> {
|
||||||
return new Promise((fulfil, reject) => {
|
return new Promise((fulfil, reject) => {
|
||||||
const requests: string[] = [];
|
const requests: string[] = [];
|
||||||
const pending: Set<string> = new Set();
|
const pending: Set<string> = new Set();
|
||||||
@@ -120,13 +151,55 @@ export class AppRunner {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
end() {
|
async intercept_requests(interceptor: (request: puppeteer.Request) => void, fn: () => any): Promise<void> {
|
||||||
return Promise.all([
|
const unique_interceptor = request => interceptor(request);
|
||||||
this.browser.close(),
|
|
||||||
new Promise(fulfil => {
|
this.page.prependListener('request', unique_interceptor);
|
||||||
this.proc.once('exit', fulfil);
|
await this.page.setRequestInterception(true);
|
||||||
this.proc.kill();
|
|
||||||
})
|
const result = await Promise.resolve(fn());
|
||||||
]);
|
|
||||||
|
await this.page.setRequestInterception(false);
|
||||||
|
this.page.removeListener('request', unique_interceptor);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
end() {
|
||||||
|
this.exiting = true;
|
||||||
|
|
||||||
|
this.server.kill();
|
||||||
|
this.browser.close();
|
||||||
|
|
||||||
|
return this.terminate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Deferred<T> extends Promise<T> {
|
||||||
|
resolve: (value?: T | PromiseLike<T>) => void;
|
||||||
|
reject: (reason?: any) => void;
|
||||||
|
settle: (result?: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function settle<T>(this: Deferred<T>, result: boolean) {
|
||||||
|
if (result) {
|
||||||
|
this.resolve();
|
||||||
|
} else {
|
||||||
|
this.reject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deferred<T>() {
|
||||||
|
let resolve, reject;
|
||||||
|
|
||||||
|
const deferred = new Promise((_resolve, _reject) => {
|
||||||
|
resolve = _resolve;
|
||||||
|
reject = _reject;
|
||||||
|
}) as Deferred<T>;
|
||||||
|
|
||||||
|
deferred.resolve = resolve;
|
||||||
|
deferred.reject = reject;
|
||||||
|
deferred.settle = settle;
|
||||||
|
|
||||||
|
return deferred;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware())
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import * as http from 'http';
|
import * as http from 'http';
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
import { wait } from '../../utils';
|
|
||||||
|
|
||||||
declare let deleted: { id: number };
|
declare let deleted: { id: number };
|
||||||
declare let el: any;
|
declare let el: any;
|
||||||
|
|
||||||
function get(url: string, opts?: any): Promise<{ headers: Record<string, string>, body: string }> {
|
type Response = { headers: http.IncomingHttpHeaders, body: string };
|
||||||
|
|
||||||
|
function get(url: string, opts: http.RequestOptions = {}): Promise<Response> {
|
||||||
return new Promise((fulfil, reject) => {
|
return new Promise((fulfil, reject) => {
|
||||||
const req = http.get(url, opts || {}, res => {
|
const req = http.get(url, opts, res => {
|
||||||
res.on('error', reject);
|
res.on('error', reject);
|
||||||
|
|
||||||
let body = '';
|
let body = '';
|
||||||
res.on('data', chunk => body += chunk);
|
res.on('data', chunk => body += chunk);
|
||||||
res.on('end', () => {
|
res.on('end', () => {
|
||||||
fulfil({
|
fulfil({
|
||||||
headers: res.headers as Record<string, string>,
|
headers: res.headers,
|
||||||
body
|
body
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -30,114 +30,104 @@ function get(url: string, opts?: any): Promise<{ headers: Record<string, string>
|
|||||||
describe('basics', function() {
|
describe('basics', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
let prefetch: (href: string) => Promise<void>;
|
|
||||||
let goto: (href: string) => Promise<void>;
|
|
||||||
let title: () => Promise<string>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, prefetchRoutes, prefetch, goto, title } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('serves /', async () => {
|
it('serves /', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'Great success!'
|
'Great success!'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('serves /?', async () => {
|
it('serves /?', async () => {
|
||||||
await page.goto(`${base}?`);
|
await r.load('/?');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'Great success!'
|
'Great success!'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('serves static route', async () => {
|
it('serves static route', async () => {
|
||||||
await page.goto(`${base}/a`);
|
await r.load('/a');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'a'
|
'a'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('serves static route from dir/index.html file', async () => {
|
it('serves static route from dir/index.html file', async () => {
|
||||||
await page.goto(`${base}/b`);
|
await r.load('/b');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'b'
|
'b'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('serves dynamic route', async () => {
|
it('serves dynamic route', async () => {
|
||||||
await page.goto(`${base}/test-slug`);
|
await r.load('/test-slug');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'TEST-SLUG'
|
'TEST-SLUG'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates to a new page without reloading', async () => {
|
it('navigates to a new page without reloading', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
const requests: string[] = await runner.capture(async () => {
|
const requests: string[] = await r.capture_requests(async () => {
|
||||||
await page.click('a[href="a"]');
|
await r.page.click('a[href="a"]');
|
||||||
|
await r.wait();
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.deepEqual(requests, []);
|
assert.deepEqual(requests, []);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'a'
|
'a'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates programmatically', async () => {
|
it('navigates programmatically', async () => {
|
||||||
await page.goto(`${base}/a`);
|
await r.load('/a');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
await r.sapper.goto('b');
|
||||||
await goto('b');
|
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'b'
|
'b'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('prefetches programmatically', async () => {
|
it('prefetches programmatically', async () => {
|
||||||
await page.goto(`${base}/a`);
|
await r.load(`/a`);
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
const requests = await runner.capture(() => prefetch('b'));
|
const requests = await r.capture_requests(() => r.sapper.prefetch('b'));
|
||||||
|
|
||||||
assert.equal(requests.length, 2);
|
assert.equal(requests.length, 2);
|
||||||
assert.equal(requests[1], `${base}/b.json`);
|
assert.equal(requests[1], `${r.base}/b.json`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO equivalent test for a webpack app
|
// TODO equivalent test for a webpack app
|
||||||
it('sets Content-Type, Link...modulepreload, and Cache-Control headers', async () => {
|
it('sets Content-Type, Link...modulepreload, and Cache-Control headers', async () => {
|
||||||
const { headers } = await get(base);
|
const { headers } = await get(r.base);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
headers['content-type'],
|
headers['content-type'],
|
||||||
@@ -157,162 +147,163 @@ describe('basics', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('calls a delete handler', async () => {
|
it('calls a delete handler', async () => {
|
||||||
await page.goto(`${base}/delete-test`);
|
await r.load('/delete-test');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
await page.click('.del');
|
await r.page.click('.del');
|
||||||
await page.waitForFunction(() => deleted);
|
await r.page.waitForFunction(() => deleted);
|
||||||
|
|
||||||
assert.equal(await page.evaluate(() => deleted.id), 42);
|
assert.equal(await r.page.evaluate(() => deleted.id), 42);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('hydrates initial route', async () => {
|
it('hydrates initial route', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
|
|
||||||
await page.evaluate(() => {
|
await r.page.evaluate(() => {
|
||||||
el = document.querySelector('.hydrate-test');
|
el = document.querySelector('.hydrate-test');
|
||||||
});
|
});
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
assert.ok(await page.evaluate(() => {
|
assert.ok(await r.page.evaluate(() => {
|
||||||
return document.querySelector('.hydrate-test') === el;
|
return document.querySelector('.hydrate-test') === el;
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not attempt client-side navigation to server routes', async () => {
|
it('does not attempt client-side navigation to server routes', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click(`[href="ambiguous/ok.json"]`);
|
await r.page.click('[href="ambiguous/ok.json"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.body.textContent),
|
await r.text('body'),
|
||||||
'ok'
|
'ok'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows reserved words as route names', async () => {
|
it('allows reserved words as route names', async () => {
|
||||||
await page.goto(`${base}/const`);
|
await r.load('/const');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'reserved words are okay as routes'
|
'reserved words are okay as routes'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts value-less query string parameter on server', async () => {
|
it('accepts value-less query string parameter on server', async () => {
|
||||||
await page.goto(`${base}/echo-query?message`);
|
await r.load('/echo-query?message');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'{"message":""}'
|
'{"message":""}'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts value-less query string parameter on client', async () => {
|
it('accepts value-less query string parameter on client', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('a[href="echo-query?message"]')
|
await r.page.click('a[href="echo-query?message"]');
|
||||||
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'{"message":""}'
|
'{"message":""}'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts duplicated query string parameter on server', async () => {
|
it('accepts duplicated query string parameter on server', async () => {
|
||||||
await page.goto(`${base}/echo-query?p=one&p=two`);
|
await r.load('/echo-query?p=one&p=two');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'{"p":["one","two"]}'
|
'{"p":["one","two"]}'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts duplicated query string parameter on client', async () => {
|
it('accepts duplicated query string parameter on client', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('a[href="echo-query?p=one&p=two"]')
|
await r.page.click('a[href="echo-query?p=one&p=two"]')
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'{"p":["one","two"]}'
|
'{"p":["one","two"]}'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// skipped because Nightmare doesn't seem to focus the <a> correctly
|
// skipped because Nightmare doesn't seem to focus the <a> correctly
|
||||||
it('resets the active element after navigation', async () => {
|
it('resets the active element after navigation', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="a"]');
|
await r.page.click('[href="a"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.activeElement.nodeName),
|
await r.page.evaluate(() => document.activeElement.nodeName),
|
||||||
'BODY'
|
'BODY'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('replaces %sapper.xxx% tags safely', async () => {
|
it('replaces %sapper.xxx% tags safely', async () => {
|
||||||
await page.goto(`${base}/unsafe-replacement`);
|
await r.load('/unsafe-replacement');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
const html = String(await page.evaluate(() => document.body.innerHTML));
|
const html = String(await r.page.evaluate(() => document.body.innerHTML));
|
||||||
assert.equal(html.indexOf('%sapper'), -1);
|
assert.equal(html.indexOf('%sapper'), -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates between routes with empty parts', async () => {
|
it('navigates between routes with empty parts', async () => {
|
||||||
await page.goto(`${base}/dirs/foo`);
|
await r.load('/dirs/foo');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
assert.equal(await title(), 'foo');
|
assert.equal(await r.text('h1'), 'foo');
|
||||||
|
|
||||||
await page.click('[href="dirs/bar"]');
|
await r.page.click('[href="dirs/bar"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
assert.equal(await title(), 'bar');
|
assert.equal(await r.text('h1'), 'bar');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates to ...rest', async () => {
|
it('navigates to ...rest', async () => {
|
||||||
await page.goto(`${base}/abc/xyz`);
|
await r.load('/abc/xyz');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
assert.equal(await title(), 'abc,xyz');
|
assert.equal(await r.text('h1'), 'abc,xyz');
|
||||||
|
|
||||||
await page.click('[href="xyz/abc/deep"]');
|
await r.page.click('[href="xyz/abc/deep"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
assert.equal(await title(), 'xyz,abc');
|
assert.equal(await r.text('h1'), 'xyz,abc');
|
||||||
|
|
||||||
await page.click(`[href="xyz/abc/qwe/deep.json"]`);
|
await r.page.click('[href="xyz/abc/qwe/deep.json"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.body.textContent),
|
await r.text('body'),
|
||||||
'xyz,abc,qwe'
|
'xyz,abc,qwe'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates between dynamic routes with same segments', async () => {
|
it('navigates between dynamic routes with same segments', async () => {
|
||||||
await page.goto(`${base}/dirs/bar/xyz`);
|
await r.load('/dirs/bar/xyz');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
assert.equal(await title(), 'A page');
|
assert.equal(await r.text('h1'), 'A page');
|
||||||
|
|
||||||
await page.click('[href="dirs/foo/xyz"]');
|
await r.page.click('[href="dirs/foo/xyz"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
assert.equal(await title(), 'B page');
|
assert.equal(await r.text('h1'), 'B page');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs server route handlers before page handlers, if they match', async () => {
|
it('runs server route handlers before page handlers, if they match', async () => {
|
||||||
const json = await get(`${base}/middleware`, {
|
const json = await get(`${r.base}/middleware`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json'
|
||||||
}
|
}
|
||||||
@@ -320,22 +311,26 @@ describe('basics', function() {
|
|||||||
|
|
||||||
assert.equal(json.body, '{"json":true}');
|
assert.equal(json.body, '{"json":true}');
|
||||||
|
|
||||||
const html = await get(`${base}/middleware`);
|
const html = await get(`${r.base}/middleware`);
|
||||||
|
|
||||||
assert.ok(html.body.indexOf('<h1>HTML</h1>') !== -1);
|
assert.ok(html.body.indexOf('<h1>HTML</h1>') !== -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalidates page when a segment is skipped', async () => {
|
it('invalidates page when a segment is skipped', async () => {
|
||||||
await page.goto(`${base}/skipped/x/1`);
|
await r.load('/skipped/x/1');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('a[href="skipped/y/1"]');
|
await r.page.click('a[href="skipped/y/1"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'y:1'
|
'y:1'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
42
test/apps/common.js
Normal file
42
test/apps/common.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
const { NODE_ENV, PORT } = process.env;
|
||||||
|
|
||||||
|
export const dev = NODE_ENV === 'development';
|
||||||
|
|
||||||
|
export function start(app) {
|
||||||
|
const port = parseInt(PORT) || 0;
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
const address = app.server.address();
|
||||||
|
|
||||||
|
process.env.PORT = address.port;
|
||||||
|
|
||||||
|
send({
|
||||||
|
__sapper__: true,
|
||||||
|
event: 'listening',
|
||||||
|
address
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const properties = ['name', 'message', 'stack', 'code', 'lineNumber', 'fileName'];
|
||||||
|
|
||||||
|
function send(message) {
|
||||||
|
process.send && process.send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_error(error) {
|
||||||
|
send({
|
||||||
|
__sapper__: true,
|
||||||
|
event: 'error',
|
||||||
|
error: properties.reduce((object, key) => ({...object, [key]: error[key]}), {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
send_error(reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('uncaughtException', err => {
|
||||||
|
send_error(err);
|
||||||
|
process.exitCode = 1;
|
||||||
|
});
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use((req, res, next) => {
|
.use((req, res, next) => {
|
||||||
// set test cookie
|
// set test cookie
|
||||||
res.setHeader('Set-Cookie', ['a=1; Max-Age=3600', 'b=2; Max-Age=3600']);
|
res.setHeader('Set-Cookie', ['a=1; Max-Age=3600', 'b=2; Max-Age=3600']);
|
||||||
next();
|
next();
|
||||||
})
|
})
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware())
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,59 +1,54 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { wait } from '../../utils';
|
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
|
|
||||||
describe('credentials', function() {
|
describe('credentials', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, prefetchRoutes } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('sends cookies when using this.fetch with credentials: "include"', async () => {
|
it('sends cookies when using this.fetch with credentials: "include"', async () => {
|
||||||
await page.goto(`${base}/credentials?creds=include`);
|
await r.load('/credentials?creds=include');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'a: 1, b: 2, max-age: undefined'
|
'a: 1, b: 2, max-age: undefined'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not send cookies when using this.fetch without credentials', async () => {
|
it('does not send cookies when using this.fetch without credentials', async () => {
|
||||||
await page.goto(`${base}/credentials`);
|
await r.load('/credentials');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'unauthorized'
|
'unauthorized'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('delegates to fetch on the client', async () => {
|
it('delegates to fetch on the client', async () => {
|
||||||
await page.goto(base)
|
await r.load('/')
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="credentials?creds=include"]');
|
await r.page.click('[href="credentials?creds=include"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'a: 1, b: 2, max-age: undefined'
|
'a: 1, b: 2, max-age: undefined'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,78 +1,61 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
import { wait } from '../../utils';
|
|
||||||
|
|
||||||
describe('css', function() {
|
describe('css', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
let prefetch: (href: string) => Promise<void>;
|
|
||||||
let goto: (href: string) => Promise<void>;
|
|
||||||
let title: () => Promise<string>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, prefetchRoutes, prefetch, goto, title } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('includes critical CSS with server render', async () => {
|
it('includes critical CSS with server render', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => {
|
await r.page.$eval('h1', node => getComputedStyle(node).color),
|
||||||
const h1 = document.querySelector('h1');
|
|
||||||
return getComputedStyle(h1).color;
|
|
||||||
}),
|
|
||||||
'rgb(255, 0, 0)'
|
'rgb(255, 0, 0)'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loads CSS when navigating client-side', async () => {
|
it('loads CSS when navigating client-side', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click(`[href="foo"]`);
|
await r.page.click(`[href="foo"]`);
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => {
|
await r.page.$eval('h1', node => getComputedStyle(node).color),
|
||||||
const h1 = document.querySelector('h1');
|
|
||||||
return getComputedStyle(h1).color;
|
|
||||||
}),
|
|
||||||
'rgb(0, 0, 255)'
|
'rgb(0, 0, 255)'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loads CSS for a lazily-rendered component', async () => {
|
it('loads CSS for a lazily-rendered component', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click(`[href="bar"]`);
|
await r.page.click(`[href="bar"]`);
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => {
|
await r.page.$eval('h1', node => getComputedStyle(node).color),
|
||||||
const h1 = document.querySelector('h1');
|
|
||||||
return getComputedStyle(h1).color;
|
|
||||||
}),
|
|
||||||
'rgb(0, 128, 0)'
|
'rgb(0, 128, 0)'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,68 +1,63 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
import { wait } from '../../utils';
|
|
||||||
|
|
||||||
describe('encoding', function() {
|
describe('encoding', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, prefetchRoutes } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('encodes routes', async () => {
|
it('encodes routes', async () => {
|
||||||
await page.goto(`${base}/fünke`);
|
await r.load('/fünke');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
`I'm afraid I just blue myself`
|
`I'm afraid I just blue myself`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes req.params and req.query for server-rendered pages', async () => {
|
it('encodes req.params and req.query for server-rendered pages', async () => {
|
||||||
await page.goto(`${base}/echo/page/encöded?message=hëllö+wörld&föo=bar&=baz&tel=%2B123456789`);
|
await r.load('/echo/page/encöded?message=hëllö+wörld&föo=bar&=baz&tel=%2B123456789');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'encöded {"message":"hëllö wörld","föo":"bar","":"baz","tel":"+123456789"}'
|
'encöded {"message":"hëllö wörld","föo":"bar","":"baz","tel":"+123456789"}'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes req.params and req.query for client-rendered pages', async () => {
|
it('encodes req.params and req.query for client-rendered pages', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('a');
|
await r.page.click('a');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'encöded {"message":"hëllö wörld","föo":"bar","":"baz","tel":"+123456789"}'
|
'encöded {"message":"hëllö wörld","föo":"bar","":"baz","tel":"+123456789"}'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes req.params for server routes', async () => {
|
it('encodes req.params for server routes', async () => {
|
||||||
await page.goto(`${base}/echo/server-route/encöded`);
|
await r.load('/echo/server-route/encöded');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'encöded'
|
'encöded'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
import { wait } from '../../utils';
|
import { wait } from '../../utils';
|
||||||
@@ -7,142 +6,137 @@ import { wait } from '../../utils';
|
|||||||
describe('errors', function() {
|
describe('errors', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
let title: () => Promise<string>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, prefetchRoutes, title } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('handles missing route on server', async () => {
|
it('handles missing route on server', async () => {
|
||||||
await page.goto(`${base}/nope`);
|
await r.load('/nope');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'404'
|
'404'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles missing route on client', async () => {
|
it('handles missing route on client', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
await page.click('[href="nope"]');
|
await r.page.click('[href="nope"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'404'
|
'404'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles explicit 4xx on server', async () => {
|
it('handles explicit 4xx on server', async () => {
|
||||||
await page.goto(`${base}/blog/nope`);
|
await r.load('/blog/nope');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'404'
|
'404'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles explicit 4xx on client', async () => {
|
it('handles explicit 4xx on client', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="blog/nope"]');
|
await r.page.click('[href="blog/nope"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'404'
|
'404'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles error on server', async () => {
|
it('handles error on server', async () => {
|
||||||
await page.goto(`${base}/throw`);
|
await r.load('/throw');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'500'
|
'500'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles error on client', async () => {
|
it('handles error on client', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="throw"]');
|
await r.page.click('[href="throw"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'500'
|
'500'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not serve error page for explicit non-page errors', async () => {
|
it('does not serve error page for explicit non-page errors', async () => {
|
||||||
await page.goto(`${base}/nope.json`);
|
await r.load('/nope.json');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.body.textContent),
|
await r.text('body'),
|
||||||
'nope'
|
'nope'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not serve error page for thrown non-page errors', async () => {
|
it('does not serve error page for thrown non-page errors', async () => {
|
||||||
await page.goto(`${base}/throw.json`);
|
await r.load('/throw.json');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.body.textContent),
|
await r.text('body'),
|
||||||
'oops'
|
'oops'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('execute error page hooks', async () => {
|
it('execute error page hooks', async () => {
|
||||||
await page.goto(`${base}/some-throw-page`);
|
await r.load('/some-throw-page');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await wait(50);
|
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h2', node => node.textContent),
|
await r.text('h2'),
|
||||||
'success'
|
'success'
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not serve error page for async non-page error', async () => {
|
it('does not serve error page for async non-page error', async () => {
|
||||||
await page.goto(`${base}/async-throw.json`);
|
await r.load('/async-throw.json');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.body.textContent),
|
await r.text('body'),
|
||||||
'oops'
|
'oops'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clears props.error on successful render', async () => {
|
it('clears props.error on successful render', async () => {
|
||||||
await page.goto(`${base}/no-error`);
|
await r.load('/no-error');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="enhance-your-calm"]');
|
await r.page.click('[href="enhance-your-calm"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
assert.equal(await title(), '420');
|
assert.equal(await r.text('h1'), '420');
|
||||||
|
|
||||||
await page.goBack();
|
await r.page.goBack();
|
||||||
await wait(50);
|
await r.wait();
|
||||||
assert.equal(await title(), 'No error here');
|
assert.equal(await r.text('h1'), 'No error here');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ import sirv from 'sirv';
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT, NODE_ENV } = process.env;
|
import { start, dev } from '../../common.js';
|
||||||
const dev = NODE_ENV === 'development';
|
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(
|
.use(
|
||||||
sirv('static', { dev }),
|
sirv('static', { dev }),
|
||||||
sapper.middleware()
|
sapper.middleware()
|
||||||
)
|
);
|
||||||
.listen(PORT, err => {
|
|
||||||
if (err) console.log('error', err);
|
start(app);
|
||||||
});
|
|
||||||
|
|||||||
@@ -6,14 +6,12 @@ describe('export-webpack', function() {
|
|||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => api.build({ cwd: __dirname, bundler: 'webpack' }));
|
||||||
await api.build({ cwd: __dirname, bundler: 'webpack' });
|
before('export app', () => api.export({ cwd: __dirname }));
|
||||||
await api.export({ cwd: __dirname, bundler: 'webpack' });
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// tests
|
||||||
it('injects <link rel=preload> tags', () => {
|
it('injects <link rel=preload> tags', () => {
|
||||||
const index = fs.readFileSync(`${__dirname}/__sapper__/export/index.html`, 'utf8');
|
const index = fs.readFileSync(`${__dirname}/__sapper__/export/index.html`, 'utf8');
|
||||||
assert.ok(/rel=preload/.test(index));
|
assert.ok(/rel=preload/.test(index));
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ import sirv from 'sirv';
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT, NODE_ENV } = process.env;
|
import { start, dev } from '../../common.js';
|
||||||
const dev = NODE_ENV === 'development';
|
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(
|
.use(
|
||||||
sirv('static', { dev }),
|
sirv('static', { dev }),
|
||||||
sapper.middleware()
|
sapper.middleware()
|
||||||
)
|
);
|
||||||
.listen(PORT, err => {
|
|
||||||
if (err) console.log('error', err);
|
start(app);
|
||||||
});
|
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ describe('export', function() {
|
|||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => api.build({ cwd: __dirname }));
|
||||||
await api.build({ cwd: __dirname });
|
before('export app', () => api.export({ cwd: __dirname }));
|
||||||
await api.export({ cwd: __dirname });
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// tests
|
||||||
it('crawls a site', () => {
|
it('crawls a site', () => {
|
||||||
const files = walk(`${__dirname}/__sapper__/export`);
|
const files = walk(`${__dirname}/__sapper__/export`);
|
||||||
|
|
||||||
@@ -45,4 +44,4 @@ describe('export', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// TODO test timeout, basepath
|
// TODO test timeout, basepath
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
const app = polka().use(sapper.middleware({
|
const app = polka().use(sapper.middleware({
|
||||||
ignore: [
|
ignore: [
|
||||||
@@ -16,4 +16,4 @@ const app = polka().use(sapper.middleware({
|
|||||||
app.get('/'+uri, (req, res) => res.end(uri));
|
app.get('/'+uri, (req, res) => res.end(uri));
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(PORT);
|
start(app);
|
||||||
|
|||||||
@@ -1,58 +1,58 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
|
|
||||||
describe('ignore', function() {
|
describe('ignore', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('respects `options.ignore` values (RegExp)', async () => {
|
it('respects `options.ignore` values (RegExp)', async () => {
|
||||||
await page.goto(`${base}/foobar`);
|
await r.load('/foobar');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.documentElement.textContent),
|
await r.text('body'),
|
||||||
'foobar'
|
'foobar'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('respects `options.ignore` values (String #1)', async () => {
|
it('respects `options.ignore` values (String #1)', async () => {
|
||||||
await page.goto(`${base}/buzz`);
|
await r.load('/buzz');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.documentElement.textContent),
|
await r.text('body'),
|
||||||
'buzz'
|
'buzz'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('respects `options.ignore` values (String #2)', async () => {
|
it('respects `options.ignore` values (String #2)', async () => {
|
||||||
await page.goto(`${base}/fizzer`);
|
await r.load('/fizzer');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.documentElement.textContent),
|
await r.text('body'),
|
||||||
'fizzer'
|
'fizzer'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('respects `options.ignore` values (Function)', async () => {
|
it('respects `options.ignore` values (Function)', async () => {
|
||||||
await page.goto(`${base}/hello`);
|
await r.load('/hello');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => document.documentElement.textContent),
|
await r.text('body'),
|
||||||
'hello'
|
'hello'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,33 +1,25 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
import { wait } from '../../utils';
|
|
||||||
|
|
||||||
describe('layout', function() {
|
describe('layout', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('only recreates components when necessary', async () => {
|
it('only recreates components when necessary', async () => {
|
||||||
await page.goto(`${base}/foo/bar/baz`);
|
await r.load('/foo/bar/baz');
|
||||||
|
|
||||||
const text1 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
const text1 = await r.text('#sapper');
|
||||||
assert.deepEqual(text1.split('\n').map(str => str.trim()).filter(Boolean), [
|
assert.deepEqual(text1.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: baz 1',
|
'z: baz 1',
|
||||||
@@ -35,8 +27,8 @@ describe('layout', function() {
|
|||||||
'child segment: baz'
|
'child segment: baz'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
const text2 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
const text2 = await r.text('#sapper');
|
||||||
assert.deepEqual(text2.split('\n').map(str => str.trim()).filter(Boolean), [
|
assert.deepEqual(text2.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: baz 1',
|
'z: baz 1',
|
||||||
@@ -44,10 +36,10 @@ describe('layout', function() {
|
|||||||
'child segment: baz'
|
'child segment: baz'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await page.click('[href="foo/bar/qux"]');
|
await r.page.click('[href="foo/bar/qux"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
const text3 = String(await page.evaluate(() => document.querySelector('#sapper').textContent));
|
const text3 = await r.text('#sapper');
|
||||||
assert.deepEqual(text3.split('\n').map(str => str.trim()).filter(Boolean), [
|
assert.deepEqual(text3.split('\n').map(str => str.trim()).filter(Boolean), [
|
||||||
'y: bar 1',
|
'y: bar 1',
|
||||||
'z: qux 2',
|
'z: qux 2',
|
||||||
@@ -55,4 +47,8 @@ describe('layout', function() {
|
|||||||
'child segment: qux'
|
'child segment: qux'
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { wait } from '../../utils';
|
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
|
|
||||||
declare const fulfil: () => Promise<void>;
|
declare const fulfil: () => Promise<void>;
|
||||||
@@ -9,112 +7,106 @@ declare const fulfil: () => Promise<void>;
|
|||||||
describe('preloading', function() {
|
describe('preloading', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
let title: () => Promise<string>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, prefetchRoutes, title } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('serializes Set objects returned from preload', async () => {
|
it('serializes Set objects returned from preload', async () => {
|
||||||
await page.goto(`${base}/preload-values/set`);
|
await r.load('/preload-values/set');
|
||||||
|
|
||||||
assert.equal(await title(), 'true');
|
assert.equal(await r.text('h1'), 'true');
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
assert.equal(await title(), 'true');
|
assert.equal(await r.text('h1'), 'true');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('prevent crash if preload return nothing', async () => {
|
it('prevent crash if preload return nothing', async () => {
|
||||||
await page.goto(`${base}/preload-nothing`);
|
await r.load('/preload-nothing');
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await wait(50);
|
|
||||||
|
|
||||||
assert.equal(await title(), 'Page loaded');
|
assert.equal(await r.text('h1'), 'Page loaded');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('bails on custom classes returned from preload', async () => {
|
it('bails on custom classes returned from preload', async () => {
|
||||||
await page.goto(`${base}/preload-values/custom-class`);
|
await r.load('/preload-values/custom-class');
|
||||||
|
|
||||||
assert.equal(await title(), '42');
|
assert.equal(await r.text('h1'), '42');
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
assert.equal(await title(), '42');
|
assert.equal(await r.text('h1'), '42');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets preloading true when appropriate', async () => {
|
it('sets preloading true when appropriate', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('a[href="slow-preload"]');
|
await r.page.click('a[href="slow-preload"]');
|
||||||
|
|
||||||
assert.ok(await page.evaluate(() => !!document.querySelector('progress')));
|
assert.ok(await r.page.evaluate(() => !!document.querySelector('progress')));
|
||||||
|
|
||||||
await page.evaluate(() => fulfil());
|
await r.page.evaluate(() => fulfil());
|
||||||
assert.ok(await page.evaluate(() => !document.querySelector('progress')));
|
assert.ok(await r.page.evaluate(() => !document.querySelector('progress')));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs preload in root component', async () => {
|
it('runs preload in root component', async () => {
|
||||||
await page.goto(`${base}/preload-root`);
|
await r.load('/preload-root');
|
||||||
assert.equal(await title(), 'root preload function ran: true');
|
assert.equal(await r.text('h1'), 'root preload function ran: true');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cancels navigation if subsequent navigation occurs during preload', async () => {
|
it('cancels navigation if subsequent navigation occurs during preload', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('a[href="slow-preload"]');
|
await r.page.click('a[href="slow-preload"]');
|
||||||
await wait(100);
|
await r.wait();
|
||||||
await page.click('a[href="foo"]');
|
await r.page.click('a[href="foo"]');
|
||||||
|
|
||||||
assert.equal(page.url(), `${base}/foo`);
|
assert.equal(r.page.url(), `${r.base}/foo`);
|
||||||
assert.equal(await title(), 'foo');
|
assert.equal(await r.text('h1'), 'foo');
|
||||||
|
|
||||||
await page.evaluate(() => fulfil());
|
await r.page.evaluate(() => fulfil());
|
||||||
await wait(100);
|
await r.wait();
|
||||||
assert.equal(page.url(), `${base}/foo`);
|
assert.equal(r.page.url(), `${r.base}/foo`);
|
||||||
assert.equal(await title(), 'foo');
|
assert.equal(await r.text('h1'), 'foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates to prefetched urls', async () => {
|
it('navigates to prefetched urls', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.hover('a[href="prefetch/qwe"]');
|
await r.page.hover('a[href="prefetch/qwe"]');
|
||||||
await wait(100);
|
await r.wait(50);
|
||||||
await page.hover('a[href="prefetch/xyz"]');
|
await r.page.hover('a[href="prefetch/xyz"]');
|
||||||
await wait(100);
|
await r.wait(50);
|
||||||
|
|
||||||
await page.click('a[href="prefetch/qwe"]');
|
await r.page.click('a[href="prefetch/qwe"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'qwe'
|
'qwe'
|
||||||
);
|
);
|
||||||
|
|
||||||
await page.goto(`${base}/prefetch`);
|
await r.load('/prefetch');
|
||||||
await wait(50);
|
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'prefetch'
|
'prefetch'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -2,138 +2,137 @@ import * as assert from 'assert';
|
|||||||
import * as puppeteer from 'puppeteer';
|
import * as puppeteer from 'puppeteer';
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
import { wait } from '../../utils';
|
|
||||||
|
|
||||||
describe('redirects', function() {
|
describe('redirects', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
let title: () => Promise<string>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, prefetchRoutes, title } = await runner.start({
|
|
||||||
requestInterceptor: (interceptedRequest) => {
|
|
||||||
if (/example\.com/.test(interceptedRequest.url())) {
|
|
||||||
interceptedRequest.respond({
|
|
||||||
status: 200,
|
|
||||||
contentType: 'text/html',
|
|
||||||
body: `<h1>external</h1>`
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
interceptedRequest.continue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('redirects on server', async () => {
|
it('redirects on server', async () => {
|
||||||
await page.goto(`${base}/redirect-from`);
|
await r.load('/redirect-from');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
page.url(),
|
r.page.url(),
|
||||||
`${base}/redirect-to`
|
`${r.base}/redirect-to`
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'redirected'
|
'redirected'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('redirects in client', async () => {
|
it('redirects in client', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="redirect-from"]');
|
await r.page.click('[href="redirect-from"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
page.url(),
|
r.page.url(),
|
||||||
`${base}/redirect-to`
|
`${r.base}/redirect-to`
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'redirected'
|
'redirected'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('redirects to root on server', async () => {
|
it('redirects to root on server', async () => {
|
||||||
await page.goto(`${base}/redirect-to-root`);
|
await r.load('/redirect-to-root');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
page.url(),
|
r.page.url(),
|
||||||
`${base}/`
|
`${r.base}/`
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'root'
|
'root'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('redirects to root in client', async () => {
|
it('redirects to root in client', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="redirect-to-root"]');
|
await r.page.click('[href="redirect-to-root"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
page.url(),
|
r.page.url(),
|
||||||
`${base}/`
|
`${r.base}/`
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'root'
|
'root'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const interceptor = (request: puppeteer.Request) => {
|
||||||
|
if (/example\.com/.test(request.url())) {
|
||||||
|
request.respond({
|
||||||
|
status: 200,
|
||||||
|
contentType: 'text/html',
|
||||||
|
body: `<h1>external</h1>`
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
request.continue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
it('redirects to external URL on server', async () => {
|
it('redirects to external URL on server', async () => {
|
||||||
await page.goto(`${base}/redirect-to-external`);
|
await r.intercept_requests(interceptor, async () => {
|
||||||
|
await r.load('/redirect-to-external');
|
||||||
|
});
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
page.url(),
|
r.page.url(),
|
||||||
`https://example.com/`
|
`https://example.com/`
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'external'
|
'external'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('redirects to external URL in client', async () => {
|
it('redirects to external URL in client', async () => {
|
||||||
await page.goto(base);
|
await r.load('/');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="redirect-to-external"]');
|
await r.intercept_requests(interceptor, async () => {
|
||||||
await wait(50);
|
await r.page.click('[href="redirect-to-external"]');
|
||||||
|
await r.wait();
|
||||||
|
});
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
page.url(),
|
r.page.url(),
|
||||||
`https://example.com/`
|
`https://example.com/`
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'external'
|
'external'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,93 +1,87 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
import { wait } from '../../utils';
|
|
||||||
|
|
||||||
describe('scroll', function() {
|
describe('scroll', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
let title: () => Promise<string>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, prefetchRoutes, title } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('scrolls to active deeplink', async () => {
|
it('scrolls to active deeplink', async () => {
|
||||||
await page.goto(`${base}/tall-page#foo`);
|
await r.load('/tall-page#foo');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
const scrollY = await page.evaluate(() => window.scrollY);
|
const scrollY = await r.page.evaluate(() => window.scrollY);
|
||||||
assert.ok(scrollY > 0, String(scrollY));
|
assert.ok(scrollY > 0, String(scrollY));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('scrolls to any deeplink if it was already active', async () => {
|
it('scrolls to any deeplink if it was already active', async () => {
|
||||||
await page.goto(`${base}/tall-page#foo`);
|
await r.load('/tall-page#foo');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
|
|
||||||
let scrollY = await page.evaluate(() => window.scrollY);
|
let scrollY = await r.page.evaluate(() => window.scrollY);
|
||||||
assert.ok(scrollY > 0, String(scrollY));
|
assert.ok(scrollY > 0, String(scrollY));
|
||||||
|
|
||||||
scrollY = await page.evaluate(() => {
|
scrollY = await r.page.evaluate(() => {
|
||||||
window.scrollTo(0, 0)
|
window.scrollTo(0, 0)
|
||||||
return window.scrollY
|
return window.scrollY
|
||||||
});
|
});
|
||||||
assert.ok(scrollY === 0, String(scrollY));
|
assert.ok(scrollY === 0, String(scrollY));
|
||||||
|
|
||||||
await page.click('[href="tall-page#foo"]');
|
await r.page.click('[href="tall-page#foo"]');
|
||||||
scrollY = await page.evaluate(() => window.scrollY);
|
scrollY = await r.page.evaluate(() => window.scrollY);
|
||||||
assert.ok(scrollY > 0, String(scrollY));
|
assert.ok(scrollY > 0, String(scrollY));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resets scroll when a link is clicked', async () => {
|
it('resets scroll when a link is clicked', async () => {
|
||||||
await page.goto(`${base}/tall-page#foo`);
|
await r.load('/tall-page#foo');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="another-tall-page"]');
|
await r.page.click('[href="another-tall-page"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.evaluate(() => window.scrollY),
|
await r.page.evaluate(() => window.scrollY),
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('preserves scroll when a link with sapper-noscroll is clicked', async () => {
|
it('preserves scroll when a link with sapper-noscroll is clicked', async () => {
|
||||||
await page.goto(`${base}/tall-page#foo`);
|
await r.load('/tall-page#foo');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="another-tall-page"][sapper-noscroll]');
|
await r.page.click('[href="another-tall-page"][sapper-noscroll]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
const scrollY = await page.evaluate(() => window.scrollY);
|
const scrollY = await r.page.evaluate(() => window.scrollY);
|
||||||
|
|
||||||
assert.ok(scrollY > 0);
|
assert.ok(scrollY > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('scrolls into a deeplink on a new page', async () => {
|
it('scrolls into a deeplink on a new page', async () => {
|
||||||
await page.goto(`${base}/tall-page#foo`);
|
await r.load('/tall-page#foo');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="another-tall-page#bar"]');
|
await r.page.click('[href="another-tall-page#bar"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
assert.equal(await title(), 'Another tall page');
|
assert.equal(await r.text('h1'), 'Another tall page');
|
||||||
const scrollY = await page.evaluate(() => window.scrollY);
|
const scrollY = await r.page.evaluate(() => window.scrollY);
|
||||||
assert.ok(scrollY > 0);
|
assert.ok(scrollY > 0);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use((req, res, next) => {
|
.use((req, res, next) => {
|
||||||
req.hello = 'hello';
|
req.hello = 'hello';
|
||||||
res.locals = { name: 'world' };
|
res.locals = { name: 'world' };
|
||||||
@@ -15,5 +15,6 @@ polka()
|
|||||||
title: `${req.hello} ${res.locals.name}`
|
title: `${req.hello} ${res.locals.name}`
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -1,50 +1,46 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import { build } from '../../../api';
|
import { build } from '../../../api';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
|
|
||||||
describe('session', function() {
|
describe('session', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let title: () => Promise<string>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
before('start runner', async () => {
|
||||||
|
r = await new AppRunner().start(__dirname);
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, page, start, title } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('renders session props', async () => {
|
it('renders session props', async () => {
|
||||||
await page.goto(`${base}/session`);
|
await r.load('/session');
|
||||||
|
|
||||||
assert.equal(await title(), 'hello world');
|
assert.equal(await r.text('h1'), 'hello world');
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
assert.equal(await title(), 'hello world');
|
assert.equal(await r.text('h1'), 'hello world');
|
||||||
|
|
||||||
await page.click('button');
|
await r.page.click('button');
|
||||||
assert.equal(await title(), 'changed');
|
assert.equal(await r.text('h1'), 'changed');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('preloads session props', async () => {
|
it('preloads session props', async () => {
|
||||||
await page.goto(`${base}/preloaded`);
|
await r.load('/preloaded');
|
||||||
|
|
||||||
assert.equal(await title(), 'hello world');
|
assert.equal(await r.text('h1'), 'hello world');
|
||||||
|
|
||||||
await start();
|
await r.sapper.start();
|
||||||
assert.equal(await title(), 'hello world');
|
assert.equal(await r.text('h1'), 'hello world');
|
||||||
|
|
||||||
await page.click('button');
|
await r.page.click('button');
|
||||||
assert.equal(await title(), 'changed');
|
assert.equal(await r.text('h1'), 'changed');
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -2,15 +2,14 @@ import sirv from 'sirv';
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT, NODE_ENV } = process.env;
|
import { start, dev } from '../../common.js';
|
||||||
const dev = NODE_ENV === 'development';
|
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(
|
.use(
|
||||||
'custom-basepath',
|
'custom-basepath',
|
||||||
sirv('static', { dev }),
|
sirv('static', { dev }),
|
||||||
sapper.middleware()
|
sapper.middleware()
|
||||||
)
|
);
|
||||||
.listen(PORT, err => {
|
|
||||||
if (err) console.log('error', err);
|
start(app);
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,51 +1,36 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as puppeteer from 'puppeteer';
|
|
||||||
import * as api from '../../../api';
|
import * as api from '../../../api';
|
||||||
import { walk } from '../../utils';
|
import { walk } from '../../utils';
|
||||||
import { AppRunner } from '../AppRunner';
|
import { AppRunner } from '../AppRunner';
|
||||||
import { wait } from '../../utils';
|
|
||||||
|
|
||||||
|
|
||||||
describe('with-basepath', function() {
|
describe('with-basepath', function() {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
let runner: AppRunner;
|
let r: AppRunner;
|
||||||
let page: puppeteer.Page;
|
|
||||||
let base: string;
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
let start: () => Promise<void>;
|
|
||||||
let prefetchRoutes: () => Promise<void>;
|
|
||||||
let title: () => Promise<string>;
|
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => api.build({ cwd: __dirname }));
|
||||||
await api.build({ cwd: __dirname });
|
before('export app', () => api.export({ cwd: __dirname, basepath: '/custom-basepath' }));
|
||||||
|
before('start runner', async () => {
|
||||||
await api.export({
|
r = await new AppRunner().start(__dirname);
|
||||||
cwd: __dirname,
|
|
||||||
basepath: '/custom-basepath'
|
|
||||||
});
|
|
||||||
|
|
||||||
runner = new AppRunner(__dirname, '__sapper__/build/server/server.js');
|
|
||||||
({ base, start, page, prefetchRoutes, title } = await runner.start());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => runner.end());
|
after(() => r && r.end());
|
||||||
|
|
||||||
|
// tests
|
||||||
it('serves /custom-basepath', async () => {
|
it('serves /custom-basepath', async () => {
|
||||||
await page.goto(`${base}/custom-basepath`);
|
await r.load('/custom-basepath');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await page.$eval('h1', node => node.textContent),
|
await r.text('h1'),
|
||||||
'Great success!'
|
'Great success!'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emits a basepath message', async () => {
|
it('emits a basepath message', async () => {
|
||||||
await page.goto(`${base}/custom-basepath`);
|
await r.load('/custom-basepath');
|
||||||
|
|
||||||
assert.deepEqual(runner.messages, [{
|
assert.deepEqual(r.messages, [{
|
||||||
__sapper__: true,
|
__sapper__: true,
|
||||||
event: 'basepath',
|
event: 'basepath',
|
||||||
basepath: '/custom-basepath'
|
basepath: '/custom-basepath'
|
||||||
@@ -71,35 +56,39 @@ describe('with-basepath', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('redirects on server', async () => {
|
it('redirects on server', async () => {
|
||||||
await page.goto(`${base}/custom-basepath/redirect-from`);
|
await r.load('/custom-basepath/redirect-from');
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
page.url(),
|
r.page.url(),
|
||||||
`${base}/custom-basepath/redirect-to`
|
`${r.base}/custom-basepath/redirect-to`
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'redirected'
|
'redirected'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('redirects in client', async () => {
|
it('redirects in client', async () => {
|
||||||
await page.goto(`${base}/custom-basepath`);
|
await r.load('/custom-basepath');
|
||||||
await start();
|
await r.sapper.start();
|
||||||
await prefetchRoutes();
|
await r.sapper.prefetchRoutes();
|
||||||
|
|
||||||
await page.click('[href="redirect-from"]');
|
await r.page.click('[href="redirect-from"]');
|
||||||
await wait(50);
|
await r.wait();
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
page.url(),
|
r.page.url(),
|
||||||
`${base}/custom-basepath/redirect-to`
|
`${r.base}/custom-basepath/redirect-to`
|
||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await title(),
|
await r.text('h1'),
|
||||||
'redirected'
|
'redirected'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it('survives the tests with no server errors', () => {
|
||||||
|
assert.deepEqual(r.errors, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ describe('with-sourcemaps-webpack', function() {
|
|||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname, bundler: 'webpack' }));
|
||||||
await build({ cwd: __dirname, bundler: 'webpack' });
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// tests
|
||||||
it('does not put sourcemap files in service worker shell', async () => {
|
it('does not put sourcemap files in service worker shell', async () => {
|
||||||
const service_worker_source = fs.readFileSync(`${__dirname}/src/node_modules/@sapper/service-worker.js`, 'utf-8');
|
const service_worker_source = fs.readFileSync(`${__dirname}/src/node_modules/@sapper/service-worker.js`, 'utf-8');
|
||||||
const shell_source = /shell = (\[[\s\S]+?\])/.exec(service_worker_source)[1];
|
const shell_source = /shell = (\[[\s\S]+?\])/.exec(service_worker_source)[1];
|
||||||
@@ -23,4 +22,4 @@ describe('with-sourcemaps-webpack', function() {
|
|||||||
const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
|
const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
|
||||||
assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
|
assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import polka from 'polka';
|
import polka from 'polka';
|
||||||
import * as sapper from '@sapper/server';
|
import * as sapper from '@sapper/server';
|
||||||
|
|
||||||
const { PORT } = process.env;
|
import { start } from '../../common.js';
|
||||||
|
|
||||||
polka()
|
const app = polka()
|
||||||
.use(sapper.middleware())
|
.use(sapper.middleware());
|
||||||
.listen(PORT);
|
|
||||||
|
start(app);
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ describe('with-sourcemaps', function() {
|
|||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
before(async () => {
|
before('build app', () => build({ cwd: __dirname }));
|
||||||
await build({ cwd: __dirname });
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// tests
|
||||||
it('does not put sourcemap files in service worker shell', async () => {
|
it('does not put sourcemap files in service worker shell', async () => {
|
||||||
const service_worker_source = fs.readFileSync(`${__dirname}/src/node_modules/@sapper/service-worker.js`, 'utf-8');
|
const service_worker_source = fs.readFileSync(`${__dirname}/src/node_modules/@sapper/service-worker.js`, 'utf-8');
|
||||||
const shell_source = /shell = (\[[\s\S]+?\])/.exec(service_worker_source)[1];
|
const shell_source = /shell = (\[[\s\S]+?\])/.exec(service_worker_source)[1];
|
||||||
@@ -23,4 +22,4 @@ describe('with-sourcemaps', function() {
|
|||||||
const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
|
const sourcemapFiles = fs.readdirSync(clientShellDir).filter(_ => _.endsWith('.map'));
|
||||||
assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
|
assert.ok(sourcemapFiles.length > 0, 'sourcemap files exist');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user