diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-02-20 21:18:31 -0500 | 
|---|---|---|
| committer | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-02-22 15:53:55 -0500 | 
| commit | 934c3239f25f9063882c82fdaf3cfa88706f908b (patch) | |
| tree | e0e58bbc99e8ad8669b86e44f7d02568fa2f654e /test | |
| parent | 85aab699e9faaf4ba93573a74d58cbce64395306 (diff) | |
Add some basic document tests
Diffstat (limited to 'test')
| -rw-r--r-- | test/data/html/test-document1.html | 106 | ||||
| -rw-r--r-- | test/data/html/test-stylesheet.css | 32 | ||||
| -rw-r--r-- | test/test-document.js | 180 | ||||
| -rw-r--r-- | test/test-stylesheet.css | 32 | 
4 files changed, 350 insertions, 0 deletions
| diff --git a/test/data/html/test-document1.html b/test/data/html/test-document1.html new file mode 100644 index 00000000..00cc8524 --- /dev/null +++ b/test/data/html/test-document1.html @@ -0,0 +1,106 @@ +<!DOCTYPE html> +<html> +    <head> +        <meta charset="UTF-8"> +        <meta name="viewport" content="width=device-width,initial-scale=1" /> +        <title>Yomichan Tests</title> +        <link rel="icon" type="image/gif" href="data:image/gif;base64,R0lGODlhEAAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAQABAAAAImFI6Zpt0B4YkS0TCpq07xbmEgcGVRUpLaI46ZG7ppalY0jDCwUAAAOw==" /> +        <link rel="stylesheet" href="test-stylesheet.css" /> +    </head> +<body> + +    <h1>Yomichan Tests</h1> + +    <div +        class="test" +        data-element-from-point-selector="span" +        data-caret-range-from-point-selector="span" +        data-start-node-selector="span" +        data-start-offset="0" +        data-end-node-selector="span" +        data-end-offset="0" +        data-result-type="TextSourceRange", +        data-sentence-extent="100" +        data-sentence="真白「心配してくださって、ありがとございます」" +    > +        <span>真白「心配してくださって、ありがとございます」</span> +    </div> + +    <div +        class="test" +        data-element-from-point-selector="span" +        data-caret-range-from-point-selector="span" +        data-start-node-selector="span" +        data-start-offset="5" +        data-end-node-selector="span" +        data-end-offset="5" +        data-result-type="TextSourceRange", +        data-sentence-extent="100" +        data-sentence="心配してくださって、ありがとございます" +    > +        <span>真白「心配してくださって、ありがとございます」</span> +    </div> + +    <div +        class="test" +        data-element-from-point-selector="input" +        data-caret-range-from-point-selector="input" +        data-start-node-selector="input" +        data-start-offset="0" +        data-end-node-selector="input" +        data-end-offset="0" +        data-result-type="TextSourceRange", +        data-sentence-extent="100" +        data-sentence="真白「心配してくださって、ありがとございます」" +        data-has-imposter="true" +    > +        <input type="text" value="真白「心配してくださって、ありがとございます」" style="width: 100%; box-sizing: border-box; font-family: inherit; font-size: inherit; border: 1px solid #d8d8d8; padding: 0.2em;" /> +    </div> + +    <div +        class="test" +        data-element-from-point-selector="textarea" +        data-caret-range-from-point-selector="textarea" +        data-start-node-selector="textarea" +        data-start-offset="0" +        data-end-node-selector="textarea" +        data-end-offset="0" +        data-result-type="TextSourceRange", +        data-sentence-extent="100" +        data-sentence="真白「心配してくださって、ありがとございます」" +        data-has-imposter="true" +    > +        <textarea style="width: 100%; height: 3em; box-sizing: border-box; font-family: inherit; font-size: inherit; border: 1px solid #d8d8d8; padding: 0.2em;">真白「心配してくださって、ありがとございます」</textarea> +    </div> + +    <div +        class="test" +        data-element-from-point-selector="button" +        data-caret-range-from-point-selector="button" +        data-start-node-selector="button" +        data-start-offset="0" +        data-end-node-selector="button" +        data-end-offset="0" +        data-result-type="TextSourceElement", +        data-sentence-extent="100" +        data-sentence="よみちゃん" +    > +        <button style="width: 100%; box-sizing: border-box; font-family: inherit; font-size: inherit; border: 1px solid #d8d8d8; background-color: #f0f0f0; padding: 0.2em;">よみちゃん</button> +    </div> + +    <div +        class="test" +        data-element-from-point-selector="img" +        data-caret-range-from-point-selector="img" +        data-start-node-selector="img" +        data-start-offset="0" +        data-end-node-selector="img" +        data-end-offset="0" +        data-result-type="TextSourceElement" +        data-sentence="よみちゃん" +    > +        <img src="data:image/gif;base64,R0lGODdhBwAHAIABAAAAAP///ywAAAAABwAHAAACDIRvEaC32FpCbEkKCgA7" alt="よみちゃん" title="よみちゃん" style="width: 70px; height: 70px; image-rendering: crisp-edges; image-rendering: pixelated; display: block;" /> +    </div> + +</body> +</html>
\ No newline at end of file diff --git a/test/data/html/test-stylesheet.css b/test/data/html/test-stylesheet.css new file mode 100644 index 00000000..ab25732e --- /dev/null +++ b/test/data/html/test-stylesheet.css @@ -0,0 +1,32 @@ +body { +    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +    font-size: 14px; +    max-width: 680px; +    padding: 0 1em; +    box-sizing: border-box; +    margin: 0 auto; +    background-color: #f8f8f8; +    counter-reset: test-id; +} + +h1 { +    font-size: 2em; +    margin: 0.67em 0; +} + +.test { +    background-color: #ffffff; +    margin: 1em 0; +    padding: 0.5em; +    box-shadow: rgba(64, 64, 64, 0.3) 0px 1px 2px 0px, rgba(64, 64, 64, 0.15) 0px 1px 3px 1px; +    border-radius: 4px; +} + +.test:before { +    content: "Test " counter(test-id); +    display: block; +    counter-increment: test-id; +    margin-bottom: 0.5em; +    border-bottom: 1px solid #d8d8d8; +    font-weight: bold; +} diff --git a/test/test-document.js b/test/test-document.js new file mode 100644 index 00000000..0c3c3d8e --- /dev/null +++ b/test/test-document.js @@ -0,0 +1,180 @@ +const fs = require('fs'); +const path = require('path'); +const assert = require('assert'); +const {JSDOM} = require('jsdom'); +const yomichanTest = require('./yomichan-test'); + + +// DOMRect class definition +class DOMRect { +    constructor(x, y, width, height) { +        this._x = x; +        this._y = y; +        this._width = width; +        this._height = height; +    } + +    get x() { return this._x; } +    get y() { return this._y; } +    get width() { return this._width; } +    get height() { return this._height; } +    get left() { return this._x + Math.min(0, this._width); } +    get right() { return this._x + Math.max(0, this._width); } +    get top() { return this._y + Math.min(0, this._height); } +    get bottom() { return this._y + Math.max(0, this._height); } +} + + +function createJSDOM(fileName) { +    const domSource = fs.readFileSync(fileName, {encoding: 'utf8'}); +    const dom = new JSDOM(domSource); +    const document = dom.window.document; +    const window = dom.window; + +    // Define innerText setter as an alias for textContent setter +    Object.defineProperty(window.HTMLDivElement.prototype, 'innerText', { +        set(value) { this.textContent = value; } +    }); + +    // Placeholder for feature detection +    document.caretRangeFromPoint = () => null; + +    return dom; +} + +function querySelectorChildOrSelf(element, selector) { +    return selector ? element.querySelector(selector) : element; +} + +function getChildTextNodeOrSelf(dom, node) { +    if (node === null) { return null; } +    const Node = dom.window.Node; +    const childNode = node.firstChild; +    return (childNode !== null && childNode.nodeType === Node.TEXT_NODE ? childNode : node); +} + +function getPrototypeOfOrNull(value) { +    try { +        return Object.getPrototypeOf(value); +    } catch (e) { +        return null; +    } +} + +function findImposterElement(document) { +    // Finds the imposter element based on it's z-index style +    return document.querySelector('div[style*="2147483646"]>*'); +} + + +async function testDocument1() { +    const dom = createJSDOM(path.join(__dirname, 'data', 'html', 'test-document1.html')); +    const window = dom.window; +    const document = window.document; +    const Node = window.Node; +    const Range = window.Range; + +    const {DOM} = yomichanTest.requireScript( +        'ext/mixed/js/dom.js', +        ['DOM'] +    ); +    const {TextSourceRange, TextSourceElement} = yomichanTest.requireScript( +        'ext/fg/js/source.js', +        ['TextSourceRange', 'TextSourceElement'], +        {document, window, Range, Node} +    ); +    const {docRangeFromPoint, docSentenceExtract} = yomichanTest.requireScript( +        'ext/fg/js/document.js', +        ['docRangeFromPoint', 'docSentenceExtract'], +        {document, window, Node, TextSourceElement, TextSourceRange, DOM} +    ); + +    try { +        await testDocument1Inner(dom, {docRangeFromPoint, docSentenceExtract, TextSourceRange, TextSourceElement}); +    } finally { +        window.close(); +    } +} + +async function testDocument1Inner(dom, {docRangeFromPoint, docSentenceExtract, TextSourceRange, TextSourceElement}) { +    const document = dom.window.document; + +    for (const testElement of document.querySelectorAll('.test')) { +        // Get test parameters +        let { +            elementFromPointSelector, +            caretRangeFromPointSelector, +            startNodeSelector, +            startOffset, +            endNodeSelector, +            endOffset, +            resultType, +            sentenceExtent, +            sentence, +            hasImposter +        } = testElement.dataset; + +        const elementFromPointValue = querySelectorChildOrSelf(testElement, elementFromPointSelector); +        const caretRangeFromPointValue = querySelectorChildOrSelf(testElement, caretRangeFromPointSelector); +        const startNode = getChildTextNodeOrSelf(dom, querySelectorChildOrSelf(testElement, startNodeSelector)); +        const endNode = getChildTextNodeOrSelf(dom, querySelectorChildOrSelf(testElement, endNodeSelector)); + +        startOffset = parseInt(startOffset, 10); +        endOffset = parseInt(endOffset, 10); +        sentenceExtent = parseInt(sentenceExtent, 10); + +        assert.notStrictEqual(elementFromPointValue, null); +        assert.notStrictEqual(caretRangeFromPointValue, null); +        assert.notStrictEqual(startNode, null); +        assert.notStrictEqual(endNode, null); + +        // Setup functions +        document.elementFromPoint = () => elementFromPointValue; + +        document.caretRangeFromPoint = (x, y) => { +            const imposter = getChildTextNodeOrSelf(dom, findImposterElement(document)); +            assert.strictEqual(!!imposter, hasImposter === 'true'); + +            const range = document.createRange(); +            range.setStart(imposter ? imposter : startNode, startOffset); +            range.setEnd(imposter ? imposter : startNode, endOffset); + +            // Override getClientRects to return a rect guaranteed to contain (x, y) +            range.getClientRects = () => [new DOMRect(x - 1, y - 1, 2, 2)]; +            return range; +        }; + +        // Test docRangeFromPoint +        const source = docRangeFromPoint(0, 0, false); +        switch (resultType) { +            case 'TextSourceRange': +                assert.strictEqual(getPrototypeOfOrNull(source), TextSourceRange.prototype); +                break; +            case 'TextSourceElement': +                assert.strictEqual(getPrototypeOfOrNull(source), TextSourceElement.prototype); +                break; +            case 'null': +                assert.strictEqual(source, null); +                break; +            default: +                assert.ok(false); +                break; +        } +        if (source === null) { continue; } + +        // Test docSentenceExtract +        const sentenceActual = docSentenceExtract(source, sentenceExtent).text; +        assert.strictEqual(sentenceActual, sentence); + +        // Clean +        source.cleanup(); +    } +} + + +async function main() { +    await testDocument1(); +} + + +if (require.main === module) { main(); } diff --git a/test/test-stylesheet.css b/test/test-stylesheet.css new file mode 100644 index 00000000..ab25732e --- /dev/null +++ b/test/test-stylesheet.css @@ -0,0 +1,32 @@ +body { +    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +    font-size: 14px; +    max-width: 680px; +    padding: 0 1em; +    box-sizing: border-box; +    margin: 0 auto; +    background-color: #f8f8f8; +    counter-reset: test-id; +} + +h1 { +    font-size: 2em; +    margin: 0.67em 0; +} + +.test { +    background-color: #ffffff; +    margin: 1em 0; +    padding: 0.5em; +    box-shadow: rgba(64, 64, 64, 0.3) 0px 1px 2px 0px, rgba(64, 64, 64, 0.15) 0px 1px 3px 1px; +    border-radius: 4px; +} + +.test:before { +    content: "Test " counter(test-id); +    display: block; +    counter-increment: test-id; +    margin-bottom: 0.5em; +    border-bottom: 1px solid #d8d8d8; +    font-weight: bold; +} |