// eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef
const puppeteer = require('puppeteer');

function wireLogs(page, prefix = '') {
    page.on('console', message =>
        console.log(`${prefix} ${message.type().substr(0, 3).toUpperCase()} ${message.text()}`))
        .on('pageerror', ({ message }) => console.error(`${prefix} ${message}`))
        .on('requestfailed', request =>
            console.error(`${prefix} ${request.failure().errorText} ${request.url()}`))
}

describe('db', () => {
    var b1;
    var b2;

    beforeAll(async () => {
        b1 = await puppeteer.launch({ headless: false });
        b2 = await puppeteer.launch({ headless: false });
    });

    var p1, p2;

    beforeEach(async () => {
        p1 = await b1.newPage();
        await p1.goto('http://localhost:3000/test/');
        p2 = await b2.newPage();
        await p2.goto('http://localhost:3000/test/');

        wireLogs(p1, 'p1');
        wireLogs(p2, 'p2');
    });

    it('should be able to retrieve a db item', async () => {
        expect.assertions(1);
        await p1.evaluate(() => window.tests.insertPerson('alice'));
        const result = await p1.evaluate(() => window.tests.getAllPersons());
        expect(result).toEqual(expect.arrayContaining([
            expect.objectContaining({ name: 'alice' })
        ]));
    });

    it('should be able to update an entry', async () => {
        expect.assertions(2);
        const entry = await p1.evaluate(() => window.tests.insertPerson('bob'));
        entry.name = 'barb';
        await p1.evaluate((p) => window.tests.updatePerson(p), entry);
        const result = await p1.evaluate(() => window.tests.getAllPersons());
        expect(result).toEqual(expect.arrayContaining([
            expect.objectContaining({ name: 'barb' })
        ]));
        expect(result).not.toEqual(expect.arrayContaining([
            expect.objectContaining({ name: 'bob' })
        ]));
    });

    it('should be able to delete an entry', async () => {
        const entry = await p1.evaluate(() => window.tests.insertPerson('homer'));
        await p1.evaluate((p) => window.tests.deletePerson(p), entry);
        const result = await p1.evaluate(() => window.tests.getAllPersons());
        expect(result).not.toEqual(expect.arrayContaining([
            expect.objectContaining({ name: 'homer' })
        ]));
    });

    it('should send and event when an entry is added', async () => {
        const result = await p1.evaluate(() => window.tests.listenForPersonChange());
        expect(result).toEqual(expect.objectContaining({ name: 'marge' }));
    });

    afterEach(async () => {
        await p1.close();
        await p2.close();
    });

    afterAll(async () => {
        await b1.close();
        await b2.close();
    })
});
