const express = require('express'); const lanthan = require('lanthan'); const path = require('path'); const assert = require('assert'); const eventually = require('./eventually'); const Key = lanthan.Key; const newApp = () => { let app = express(); app.get('/', (req, res) => { res.send(`<!DOCTYPEhtml> <html lang="en"> <body><a href="hello">hello</a></body> </html">`); }); app.get('/follow-input', (req, res) => { res.send(`<!DOCTYPEhtml> <html lang="en"> <body><input></body> </html">`); }); app.get('/area', (req, res) => { res.send(`<!DOCTYPEhtml> <html lang="en"> <body> <img width="256" height="256" usemap="#map" src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=" > <map name="map"> <area shape="rect" coords="0,0,64,64" href="/"> <area shape="rect" coords="64,64,64,64" href="/"> <area shape="rect" coords="128,128,64,64" href="/"> </map> </body> </html">`); }); /* * test case: link2 is out of the viewport * +-----------------+ * | [link1] |<--- window * | | * |=================|<--- viewport * | [link2] | * | | * +-----------------+ */ app.get('/test1', (req, res) => { res.send(`<!DOCTYPEhtml> <html lang="en"> <body> <div><a href="link1">link1</a></div> <div style="min-height:3000px"></div> <div><a href="link2">link2</a></div> </body> </html">`); }); /* * test case 2: link2 and link3 are out of window of the frame * +-----------------+ * | +-----------+ | * | | [link1] | | * |=================| * | | [link2] | | * | +-----------+ | * | | * +-----------------+ */ app.get('/test2', (req, res) => { res.send(`<!DOCTYPEhtml> <html lang="en"> <body><iframe height="5000" src='/test2-frame'></body> </html">`); }); app.get('/test2-frame', (req, res) => { res.send(`<!DOCTYPEhtml> <html lang="en"> <body> <div><a href="link1">link1</a></div> <div style="min-height:3000px"></div> <div><a href="link2">link2</a></div> </body> </html">`); }); /* test case 3: link2 is out of window of the frame * +-----------------+ * | +-----------+ | * | | [link1] | | * | +-----------+ | * | : [link2] : | * | + - - - - - + | * | | * +-----------------+ */ app.get('/test3', (req, res) => { res.send(`<!DOCTYPEhtml> <html lang="en"> <body><iframe src='/test3-frame'></body> </html">`); }); app.get('/test3-frame', (req, res) => { res.send(`<!DOCTYPEhtml> <html lang="en"> <body> <div><a href="link1">link1</a></div> <div style="min-height:3000px"></div> <div><a href="link2">link2</a></div> </body> </html">`); }); return app; }; const waitForHints = async(session) => { await eventually(async() => { let hints = await session.findElementsByCSS('.vimvixen-hint'); assert(hints.length > 0); }); }; describe('follow test', () => { const port = 12321; let http; let firefox; let session; let browser; before(async() => { http = newApp().listen(port); firefox = await lanthan.firefox(); await firefox.session.installAddonFromPath(path.join(__dirname, '..')); session = firefox.session; browser = firefox.browser; }); after(async() => { if (firefox) { await firefox.close(); } http.close(); }); afterEach(async() => { let tabs = await browser.tabs.query({}); for (let tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); } }); it('should focus an input by f', async () => { await session.navigateTo(`http://127.0.0.1:${port}/follow-input`); let body = await session.findElementByCSS('body'); await body.sendKeys('f'); await waitForHints(session); await body.sendKeys('a'); let tagName = await session.executeScript(() => document.activeElement.tagName); assert.equal(tagName.toLowerCase(), 'input'); }); it('should open a link by f', async () => { await session.navigateTo(`http://127.0.0.1:${port}/`); let body = await session.findElementByCSS('body'); await body.sendKeys('f', 'a'); let hash = await session.executeScript('location.pathname'); await body.sendKeys(hash, '/hello'); }); it('should focus an input by F', async () => { await session.navigateTo(`http://127.0.0.1:${port}/follow-input`); let body = await session.findElementByCSS('body'); await body.sendKeys(Key.Shift, 'f'); await waitForHints(session); await body.sendKeys('a'); let tagName = await session.executeScript(() => document.activeElement.tagName); assert.equal(tagName.toLowerCase(), 'input'); }); it('should open a link to new tab by F', async () => { await session.navigateTo(`http://127.0.0.1:${port}/`); let body = await session.findElementByCSS('body'); await body.sendKeys(Key.Shift, 'f'); await waitForHints(session); await body.sendKeys('a'); await eventually(async() => { let tabs = await browser.tabs.query({}); assert.equal(tabs.length, 2); assert.equal(new URL(tabs[1].url).pathname, '/hello'); assert.equal(tabs[1].openerTabId, tabs[0].id); }); }); it('should show hints of links in area', async () => { await session.navigateTo(`http://127.0.0.1:${port}/area`); let body = await session.findElementByCSS('body'); await body.sendKeys(Key.Shift, 'f'); await eventually(async() => { let hints = await session.findElementsByCSS('.vimvixen-hint'); assert.equal(hints.length, 3); }); }); it('should shows hints only in viewport', async () => { await session.navigateTo(`http://127.0.0.1:${port}/test1`); let body = await session.findElementByCSS('body'); await body.sendKeys(Key.Shift, 'f'); await eventually(async() => { let hints = await session.findElementsByCSS('.vimvixen-hint'); assert.equal(hints.length, 1); }); }); it('should shows hints only in window of the frame', async () => { await session.navigateTo(`http://127.0.0.1:${port}/test2`); let body = await session.findElementByCSS('body'); await body.sendKeys(Key.Shift, 'f'); await session.switchToFrame(0); await eventually(async() => { let hints = await session.findElementsByCSS('.vimvixen-hint'); assert.equal(hints.length, 1); }); }); it('should shows hints only in the frame', async () => { await session.navigateTo(`http://127.0.0.1:${port}/test3`); let body = await session.findElementByCSS('body'); await body.sendKeys(Key.Shift, 'f'); await session.switchToFrame(0); await eventually(async() => { let hints = await session.findElementsByCSS('.vimvixen-hint'); assert.equal(hints.length, 1); }); }); });