🏡 index : quine-global/webdriverio.git

import { describe, expect, vi, beforeAll, afterAll, afterEach, it } from 'vitest'
import { startServer, __store, __resourcePoolStore } from '../src/server.js'

const errHandler = vi.fn()

const headers = {
    'Content-Type': 'application/json'
}

describe('WdioSharedStoreService exports', () => {
    let setUrl: string
    let getUrl: string
    let result: {
        port: number;
        app: PolkaInstance;
    } | undefined
    let setResourcePoolUrl: string
    let getValueFromPoolUrl: string
    let addValueToPoolUrl: string

    beforeAll(async () => {
        vi.unstubAllGlobals()
        result = await startServer()
        const baseUrl = `http://localhost:${result.port}`
        setUrl = `${baseUrl}/`
        getUrl = `${baseUrl}`
        setResourcePoolUrl = `${baseUrl}/pool/`
        getValueFromPoolUrl = `${baseUrl}/pool`
        addValueToPoolUrl = `${baseUrl}/pool`
    })

    it('should not fail if payload has no key/value', async () => {
        await fetch(setUrl, { method: 'post', body: JSON.stringify({}), headers })
        await fetch(getUrl, { method: 'post', body: JSON.stringify({}), headers })
        expect(__store).toEqual({})
    })

    it('should handle non json type', async () => {
        const response = await fetch(getUrl, { method: 'post', body: 'foobar', headers })
        expect(response.status).toBe(422)
        expect(response.statusText).toBe('Unprocessable Entity')
        expect(response.url).toContain('/')
        expect(await response.text()).toBe('Invalid JSON')
    })

    it('should handle 404', async () => {
        const response = await fetch(`${getUrl}/foo/bar`, { method: 'get', headers })
        expect(response.status).toBe(404)
    })

    describe('setting/getting entries', () => {
        it('should set entry', async () => {
            await fetch(setUrl, {
                method: 'post',
                body: JSON.stringify({ key: 'foo', value: 'bar' }),
                headers
            })
            expect(__store).toEqual({ foo: 'bar' })
        })

        it('should get entry', async () => {
            __store.foobar = 'barfoo'
            const res = await fetch(`${getUrl}/foobar`, { method: 'get', headers })
            expect((await res.json()).value).toEqual('barfoo')
        })
    })

    describe('resource pools', () => {
        describe('when calling setResourcePool with an array', () => {
            it('should initialize that value in the store', async () => {
                const response = await fetch(setResourcePoolUrl, { method: 'post', body: JSON.stringify({ key: 'foo', value: ['bar'] }), headers })
                expect(response.status).toBe(200)
                expect(Array.from(__resourcePoolStore.entries())).toEqual([['foo', ['bar']]])
            })
        })

        describe('when calling setResourcePool without an array', () => {
            it('should throw an error', async () => {
                const response = await fetch(setResourcePoolUrl, { method: 'post', body: JSON.stringify({ key: 'foo', value: 'bar' }), headers })
                expect(response.status).toBe(500)
                expect((await response.text())).toBe('Resource pool must be an array of values')
            })
        })

        describe('when calling setResourcePool with an already existing key', () => {
            it('should should override it', async () => {
                await fetch(setResourcePoolUrl, { method: 'post', body: JSON.stringify({ key: 'foo', value: [] }), headers })
                await fetch(setResourcePoolUrl, { method: 'post', body: JSON.stringify({ key: 'foo', value: ['bar'] }), headers })
                expect(Array.from(__resourcePoolStore.entries())).toEqual([['foo', ['bar']]])
            })
        })

        describe('when calling getValueFromPool with the name of an existing pool', () => {
            it('should return the first element and update the store', async () => {
                __resourcePoolStore.set('foo', ['bar'])
                const response = await fetch(`${getValueFromPoolUrl}/foo`, { method: 'get', headers })
                expect((await response.json()).value).toEqual('bar')
                expect(Array.from(__resourcePoolStore.entries())).toEqual([['foo', []]])
            })

            describe('and the pool will receive values after calling', () => {
                describe('and the timeout has a specified value', () => {
                    it('should return a value within the specified timeout', async () => {
                        __resourcePoolStore.set('foo', [])
                        const promise = fetch(`${getValueFromPoolUrl}/foo?timeout=200`, { method: 'get', headers })
                        await new Promise(resolve => setTimeout(resolve, 10))
                        __resourcePoolStore.set('foo', ['bar'])
                        const response = await promise
                        expect(response.status).toBe(200)
                        expect((await response.json()).value).toEqual('bar')
                        expect(Array.from(__resourcePoolStore.entries())).toEqual([['foo', []]])
                    })
                })

                describe('and the timeout is not specified', () => {
                    it('should return a value within the default timeout', async () => {
                        __resourcePoolStore.set('foo', [])
                        const promise = fetch(`${getValueFromPoolUrl}/foo`, { method: 'get', headers })
                        await new Promise(resolve => setTimeout(resolve, 10))
                        __resourcePoolStore.set('foo', ['bar'])
                        const response = await promise
                        expect(response.status).toBe(200)
                        expect((await response.json()).value).toEqual('bar')
                        expect(Array.from(__resourcePoolStore.entries())).toEqual([['foo', []]])
                    })
                })
            })
        })

        describe('when calling getValueFromPool with the name of a non existing pool', () => {
            it('should throw an error', async () => {
                const response = await fetch(`${getValueFromPoolUrl}/foo`, { method: 'get', headers })
                expect(response.status).toBe(500)
                expect(response.statusText).toBe('Internal Server Error')
                expect(await response.text()).toBe("'foo' resource pool does not exist. Set it first using 'setResourcePool'")
                expect(Array.from(__resourcePoolStore.entries())).toEqual([])
            })
        })

        describe('when calling addValueToPool with a value and valid pool name', () => {
            it('should add that value to the pool', async () => {
                __resourcePoolStore.set('foo', [])
                const response = await fetch(addValueToPoolUrl + '/foo', { method: 'post', body: JSON.stringify({ value: 'bar' }), headers })
                expect(response.status).toBe(200)
                expect(Array.from(__resourcePoolStore.entries())).toEqual([['foo', ['bar']]])
            })
        })

        describe('when calling addValueToPool with an invalid pool name', () => {
            it('should throw an error', async () => {
                const response = await fetch(addValueToPoolUrl + '/foo', { method: 'post', body: JSON.stringify({ value: 'bar' }), headers })
                expect(response.status).toBe(500)
                expect(await response.text()).toBe("'foo' resource pool does not exist. Set it first using 'setResourcePool'")
            })
        })
    })

    afterEach(() => {
        Object.keys(__store).forEach(key => { delete __store[key] })
        __resourcePoolStore.clear()
        errHandler.mockClear()
    })

    afterAll(async () => {
        return new Promise((resolve) => {
            if (result?.app.server.close) {
                return result?.app.server.close(() => resolve())
            }
            resolve()
        })
    })
})