commit
e9a6fb8558
13 changed files with 479 additions and 64 deletions
@ -0,0 +1,121 @@ |
|||||||
|
import * as windows from "../ambassador/src/client/windows"; |
||||||
|
import * as tabs from "../ambassador/src/client/tabs"; |
||||||
|
import * as keys from "../ambassador/src/client/keys"; |
||||||
|
import { CLIENT_URL } from '../web-server/url'; |
||||||
|
|
||||||
|
describe("tab test", () => { |
||||||
|
let targetWindow; |
||||||
|
|
||||||
|
beforeEach(() => { |
||||||
|
return windows.create(CLIENT_URL).then((win) => { |
||||||
|
targetWindow = win; |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
afterEach(() => { |
||||||
|
return windows.remove(targetWindow.id); |
||||||
|
}); |
||||||
|
|
||||||
|
it('follows link by `f`', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/follow').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'f'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'a'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/follow#a'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
it('follows link into new tab by `F`', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/follow').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'F', { shiftKey: true }); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'a'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 500) }); |
||||||
|
}).then(() => { |
||||||
|
return windows.get(targetWindow.id); |
||||||
|
}).then((win) => { |
||||||
|
let urls = win.tabs.map(t => t.url); |
||||||
|
expect(urls).to.have.lengthOf(3); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/'); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/follow'); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/follow#a'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
it('follows link with target=_blank into new tab by `f`', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/follow').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'f'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'b'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 500) }); |
||||||
|
}).then(() => { |
||||||
|
return windows.get(targetWindow.id); |
||||||
|
}).then((win) => { |
||||||
|
let urls = win.tabs.map(t => t.url); |
||||||
|
expect(urls).to.have.lengthOf(3); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/'); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/follow'); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/follow#external'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
it('follows link with target=_blank into new tab by `F`', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/follow').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'F', { shiftKey: true }); |
||||||
|
}).then(() => { |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'b'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 500) }); |
||||||
|
}).then(() => { |
||||||
|
return windows.get(targetWindow.id); |
||||||
|
}).then((win) => { |
||||||
|
let urls = win.tabs.map(t => t.url); |
||||||
|
expect(urls).to.have.lengthOf(3); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/'); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/follow'); |
||||||
|
expect(urls).to.include(CLIENT_URL + '/follow#external'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
it('follows area by `F`', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/follow').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'f'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'c'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/follow#area'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
@ -0,0 +1,156 @@ |
|||||||
|
import * as windows from "../ambassador/src/client/windows"; |
||||||
|
import * as tabs from "../ambassador/src/client/tabs"; |
||||||
|
import * as keys from "../ambassador/src/client/keys"; |
||||||
|
import * as scrolls from "../ambassador/src/client/scrolls"; |
||||||
|
import { CLIENT_URL } from '../web-server/url'; |
||||||
|
|
||||||
|
describe("navigate test", () => { |
||||||
|
let targetWindow; |
||||||
|
|
||||||
|
before(() => { |
||||||
|
return windows.create().then((win) => { |
||||||
|
targetWindow = win; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
after(() => { |
||||||
|
return windows.remove(targetWindow.id); |
||||||
|
}); |
||||||
|
|
||||||
|
it('goes to parent', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/a/b/c').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'g'); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'u'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/a/b/'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
it('removes hash', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/a/b/c#navigate').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'g'); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'u'); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/a/b/c#'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
it('goes to root', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/a/b/c').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'g'); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'U', { shiftKey: true }); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
it('goes back and forward in history', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/#navigate').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, 'g'); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'u'); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'H', { shiftKey: true }); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url, 'go back in history').to.be.equal(CLIENT_URL + '/#navigate'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, 'L', { shiftKey: true }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url, 'go next in history').to.be.equal(CLIENT_URL + '/#'); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
it('goes previous page by <a>', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/a-pagenation?page=10').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, '['); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, '['); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/a-pagenation?page=9'); |
||||||
|
}); |
||||||
|
}) |
||||||
|
|
||||||
|
it('goes next page by <a>', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/a-pagenation?page=10').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, ']'); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, ']'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/a-pagenation?page=11'); |
||||||
|
}); |
||||||
|
}) |
||||||
|
|
||||||
|
it('goes previous page by <link>', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/link-pagenation?page=10').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, '['); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, '['); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/link-pagenation?page=9'); |
||||||
|
}); |
||||||
|
}) |
||||||
|
|
||||||
|
it('goes next page by <link>', () => { |
||||||
|
let targetTab; |
||||||
|
return tabs.create(targetWindow.id, CLIENT_URL + '/link-pagenation?page=10').then((tab) => { |
||||||
|
targetTab = tab; |
||||||
|
return keys.press(targetTab.id, ']'); |
||||||
|
}).then(() => { |
||||||
|
return keys.press(targetTab.id, ']'); |
||||||
|
}).then(() => { |
||||||
|
return new Promise(resolve => { setTimeout(() => resolve(), 10) }); |
||||||
|
}).then(() => { |
||||||
|
return tabs.get(targetTab.id); |
||||||
|
}).then((tab) => { |
||||||
|
expect(tab.url).to.be.equal(CLIENT_URL + '/link-pagenation?page=11'); |
||||||
|
}); |
||||||
|
}) |
||||||
|
}); |
@ -1,14 +1,88 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
var serverUrl = require('./url'); |
||||||
var http = require('http'); |
var http = require('http'); |
||||||
|
var url = require('url'); |
||||||
|
|
||||||
const content = |
const handleScroll = (req, res) => { |
||||||
'<!DOCTYPE html>' + |
res.writeHead(200, {'Content-Type': 'text/html'}); |
||||||
'<html lang="en">' + |
res.end('<!DOCTYPEhtml><html lang="en"><body style="width:10000px; height:10000px"></body></html">'); |
||||||
'<body style="width:10000px; height:10000px">' + |
}; |
||||||
'</body>' + |
|
||||||
'</html">' ; |
|
||||||
|
|
||||||
|
const handleAPagenation = (req, res) => { |
||||||
|
let u = url.parse(req.url); |
||||||
|
let params = new url.URLSearchParams(u.search); |
||||||
|
let page = params.get('page') === null ? null : Number(params.get('page')); |
||||||
|
if (page === null || isNaN(page)) { |
||||||
|
return handle404(req, res); |
||||||
|
} |
||||||
|
|
||||||
|
let body = ''; |
||||||
|
let nextLink = u.pathname + '?page=' + (page + 1); |
||||||
|
let prevLink = u.pathname + '?page=' + (page - 1); |
||||||
|
|
||||||
|
if (page > 1) { |
||||||
|
body += '<a href="' + prevLink + '">prev</a> | '; |
||||||
|
} |
||||||
|
body += '<a href="' + nextLink + '">next</a>'; |
||||||
|
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/html'}); |
||||||
|
res.end('<!DOCTYPEhtml><html lang="en"><body">' + body + '</body></html">'); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleLinkPagenation = (req, res) => { |
||||||
|
let u = url.parse(req.url); |
||||||
|
let params = new url.URLSearchParams(u.search); |
||||||
|
let page = params.get('page') === null ? null : Number(params.get('page')); |
||||||
|
if (page === null || isNaN(page)) { |
||||||
|
return handle404(req, res); |
||||||
|
} |
||||||
|
|
||||||
|
let head = ''; |
||||||
|
let nextLink = u.pathname + '?page=' + (page + 1); |
||||||
|
let prevLink = u.pathname + '?page=' + (page - 1); |
||||||
|
|
||||||
|
if (page > 1) { |
||||||
|
head += '<link rel="prev" href="' + prevLink + '"></link>'; |
||||||
|
} |
||||||
|
head += '<link rel="next" href="' + nextLink + '"></link>'; |
||||||
|
|
||||||
http.createServer(function (req, res) { |
|
||||||
res.writeHead(200, {'Content-Type': 'text/html'}); |
res.writeHead(200, {'Content-Type': 'text/html'}); |
||||||
res.end(content); |
res.end('<!DOCTYPEhtml><html lang="en"><head>' + head + '</head><body"></body></html">'); |
||||||
}).listen(11111, '127.0.0.1'); |
}; |
||||||
|
|
||||||
|
const handleFollow = (req, res) => { |
||||||
|
let body = ''; |
||||||
|
body += '<a href="#a">a</a>'; |
||||||
|
body += '<a href="#external" target="_blank">external</a>'; |
||||||
|
body += '<img width="320" height="240" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" usemap="#map"><map name="map"><area href="#area" shape="rect" coords="15,19,126,104"></map>' |
||||||
|
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/html'}); |
||||||
|
res.end('<!DOCTYPEhtml><html lang="en"><body">' + body + '</body></html">'); |
||||||
|
} |
||||||
|
|
||||||
|
const handle404 = (req, res) => { |
||||||
|
res.writeHead(404, {'Content-Type': 'text/plain'}); |
||||||
|
res.end('not found') |
||||||
|
}; |
||||||
|
|
||||||
|
http.createServer(function (req, res) { |
||||||
|
if (req.method !== 'GET') { |
||||||
|
handle404(req, res); |
||||||
|
} |
||||||
|
|
||||||
|
let u = url.parse(req.url); |
||||||
|
if (u.pathname === '/scroll') { |
||||||
|
handleScroll(req, res); |
||||||
|
} else if (u.pathname === '/a-pagenation') { |
||||||
|
handleAPagenation(req, res); |
||||||
|
} else if (u.pathname === '/link-pagenation') { |
||||||
|
handleLinkPagenation(req, res); |
||||||
|
} else if (u.pathname === '/follow') { |
||||||
|
handleFollow(req, res); |
||||||
|
} else { |
||||||
|
handle404(req, res); |
||||||
|
} |
||||||
|
|
||||||
|
console.log(`"${req.method} ${req.url}"`, res.statusCode) |
||||||
|
}).listen(serverUrl.PORT, serverUrl.HOST); |
||||||
|
@ -0,0 +1,5 @@ |
|||||||
|
module.exports = { |
||||||
|
PORT: 11111, |
||||||
|
HOST: '127.0.0.1', |
||||||
|
CLIENT_URL: 'http://127.0.0.1:11111', |
||||||
|
} |
Reference in new issue