<|start_filename|>Makefile<|end_filename|>
.DEFAULT_GOAL := help

.PHONY: build \
		ci \
		clean \
		help \
		install \
		reload \
		test \
		tree \
		watch

.SILENT:

# generate assets
build: tree
	tasks/build

# continuous integration
ci: install \
	build \
	test

# clean generated assets
clean:
	tasks/clean

# show some help
help:
	tasks/help

# install project dependencies
install:
	tasks/install

# issue a reload signal to nginx
reload:
	tasks/reload

# run tests
test:
	tasks/test

# generate the public file tree
tree:
	tasks/tree

# generate assets on asset changes
watch:
	tasks/watch


<|start_filename|>client/scripts/custom-element.js<|end_filename|>
export default ParentClass => class CustomElement extends ParentClass {
    static define() {
        customElements.define(this.tagName, this, {
            extends: this.tagType
        })
    }

    connectedCallback() {
        if (this.isConnected && this.mount instanceof Function) {
            this.mount()
        }
    }

    getCustomElement(customElement) {
        return this.querySelector(`[is="${customElement.tagName}"]`)
    }
}


<|start_filename|>client/scripts/main.js<|end_filename|>
import AssetLink from './asset-link'
import AssetItem from './asset-item'
import AssetList from './asset-list'

function main() {
    AssetLink.define()
    AssetItem.define()
    AssetList.define()
}

document.addEventListener('DOMContentLoaded', main)


<|start_filename|>tests/helper.js<|end_filename|>
exports.getActiveElementText = (page) => {
    return page.evaluate(() => {
        return document.activeElement.textContent
    })
}

exports.getExpectedList = () => {
    return [{
        // 0
        highlighted: false,
        name: 'phasellus',
        type: 'directory'
    }, {
        // 1
        highlighted: false,
        name: 'fusce',
        type: 'directory'
    }, {
        // 2
        highlighted: false,
        name: 'orci',
        type: 'directory'
    }, {
        // 3
        highlighted: false,
        name: 'sed',
        type: 'file'
    }, {
        // 4
        highlighted: false,
        name: 'etiam',
        type: 'file'
    }, {
        // 5
        highlighted: false,
        name: 'pellentesque',
        type: 'file'
    }]
}

exports.getResultList = (page) => {
    return page.evaluate(() => {
        const assetList = document.body.querySelector('[is="asset-list"]')
        const list = [ ]

        for (const assetItem of assetList.children) {
            list.push({
                highlighted: assetItem.link.highlighted,
                name: assetItem.link.textContent,
                type: assetItem.link.type
            })
        }

        return list
    })
}


<|start_filename|>tests/main.js<|end_filename|>
const path = require('path')
const puppeteer = require('puppeteer')
const { getActiveElementText, getExpectedList, getResultList } = require('./helper')

let browser = undefined
let page = undefined

describe('ngx-superbindex', () => {
    beforeAll(async () => {
        browser = await puppeteer.launch({
            args: ['--allow-file-access-from-files']
        })

        page = await browser.newPage()
    })

    beforeEach(async () => {
        const fixture = path.join(__dirname, 'fixture.xml')
        await page.goto(`file://${fixture}`)
    })

    describe('search as you type', () => {
        it('p, h, escape', async () => {
            await page.keyboard.press('p');
            const expectedListA = getExpectedList()
            const resultListA = await getResultList(page)
            expectedListA[0].highlighted = true
            expectedListA[5].highlighted = true
            expect(resultListA).withContext('after pressing p').toEqual(expectedListA)

            await page.keyboard.press('h');
            const expectedListB = getExpectedList()
            const resultListB = await getResultList(page)
            expectedListB[0].highlighted = true
            expect(resultListB).withContext('after pressing h').toEqual(expectedListB)

            await page.keyboard.press('Escape');
            const expectedListC = getExpectedList()
            const resultListC = await getResultList(page)
            expect(resultListC).withContext('after pressing escape').toEqual(expectedListC)
        })

        it('s, e, d, x', async () => {
            await page.keyboard.type('sed');
            const expectedListA = getExpectedList()
            const resultListA = await getResultList(page)
            expectedListA[3].highlighted = true
            expect(resultListA).withContext('after typing sed').toEqual(expectedListA)

            await page.keyboard.press('x');
            const expectedListB = getExpectedList()
            const resultListB = await getResultList(page)
            expect(resultListB).withContext('after pressing x').toEqual(expectedListB)
        })
    })

    describe('tab focus', () => {
        it('p, e, escape', async () => {
            const expectedList = getExpectedList()

            await page.keyboard.press('p');
            const activeElementTextA = await getActiveElementText(page)
            expect(activeElementTextA).withContext('after pressing p').toBe(expectedList[0].name)

            await page.keyboard.press('e');
            const activeElementTextB = await getActiveElementText(page)
            expect(activeElementTextB).withContext('after pressing e').toBe(expectedList[5].name)

            await page.keyboard.press('Escape');
            const activeElementTextC = await getActiveElementText(page)
            expect(activeElementTextC).withContext('after pressing escape').toBe(expectedList[5].name)
        })

        it('s, e, d, x', async () => {
            const expectedList = getExpectedList()

            await page.keyboard.type('sed');
            const activeElementTextA = await getActiveElementText(page)
            expect(activeElementTextA).withContext('after typing sed').toBe(expectedList[3].name)

            await page.keyboard.press('x');
            const activeElementTextB = await getActiveElementText(page)
            expect(activeElementTextB).withContext('after pressing x').toBe(expectedList[3].name)
        })
    })

    afterAll(async () => {
        await browser.close()
    })
})
