浏览代码

add mainMenuBuilder.test.ts and sseSource.test.ts

Olivier Massot 2 年之前
父节点
当前提交
0172ffccfa

+ 7 - 7
services/sse/sseSource.ts

@@ -1,12 +1,12 @@
 import { EventSourcePolyfill } from "event-source-polyfill";
 
 class SseSource {
-  private readonly url: URL
-  private readonly onOpen: (() => void)
-  private readonly onMessage: ((eventData: Array<any>) => void)
-  private readonly onClose: (() => void)
-  private readonly withCredentials: boolean
-  protected eventSource: EventSource | null = null
+  protected readonly url: URL
+  protected readonly onOpen: (() => void)
+  protected readonly onMessage: ((eventData: Array<any>) => void)
+  protected readonly onClose: (() => void)
+  protected readonly withCredentials: boolean
+  protected eventSource: EventSourcePolyfill | null = null
 
   constructor(
     mercureHubBaseUrl: string,
@@ -62,7 +62,7 @@ class SseSource {
   }
 
   public unsubscribe () {
-    if (this.eventSource === null || this.eventSource.readyState === EventSource.CLOSED) {
+    if (this.eventSource === null || this.eventSource.readyState === EventSourcePolyfill.CLOSED) {
       return
     }
     this.eventSource.close()

+ 105 - 0
tests/units/services/menuBuilder/mainMenuBuilder.test.ts

@@ -0,0 +1,105 @@
+import { describe, test, it, expect } from 'vitest'
+import {RuntimeConfig} from "@nuxt/schema";
+import {AnyAbility} from "@casl/ability/dist/types";
+import {AccessProfile, organizationState} from "~/types/interfaces";
+import MainMenuBuilder from "~/services/menuBuilder/mainMenuBuilder";
+import {MenuGroup, MenuItem} from "~/types/layout";
+import {MENU_LINK_TYPE} from "~/types/enum/layout";
+import AbstractMenuBuilder from "~/services/menuBuilder/abstractMenuBuilder";
+import AccessMenuBuilder from "~/services/menuBuilder/accessMenuBuilder";
+import AgendaMenuBuilder from "~/services/menuBuilder/agendaMenuBuilder";
+import EquipmentMenuBuilder from "~/services/menuBuilder/equipmentMenuBuilder";
+import EducationalMenuBuilder from "~/services/menuBuilder/educationalMenuBuilder";
+import BillingMenuBuilder from "~/services/menuBuilder/billingMenuBuilder";
+import CommunicationMenuBuilder from "~/services/menuBuilder/communicationMenuBuilder";
+import DonorsMenuBuilder from "~/services/menuBuilder/donorsMenuBuilder";
+import MedalsMenuBuilder from "~/services/menuBuilder/medalsMenuBuilder";
+import WebsiteAdminMenuBuilder from "~/services/menuBuilder/websiteAdminMenuBuilder";
+import CotisationsMenuBuilder from "~/services/menuBuilder/cotisationsMenuBuilder";
+import StatsMenuBuilder from "~/services/menuBuilder/statsMenuBuilder";
+import Admin2iosMenuBuilder from "~/services/menuBuilder/admin2iosMenuBuilder";
+
+let runtimeConfig: RuntimeConfig
+let ability: AnyAbility
+let organizationProfile: organizationState
+let accessProfile: AccessProfile
+let menuBuilder: TestableMainMenuBuilder
+
+class TestableMainMenuBuilder extends MainMenuBuilder {
+    public buildSubmenu(menuBuilder: typeof AbstractMenuBuilder) {
+        return super.buildSubmenu(menuBuilder)
+    }
+}
+
+
+beforeEach(()=> {
+    runtimeConfig = vi.fn() as any as RuntimeConfig
+    ability = vi.fn() as any as AnyAbility
+    organizationProfile = vi.fn() as any as organizationState
+    accessProfile = vi.fn() as any as AccessProfile
+
+    runtimeConfig.baseUrlAdminLegacy = 'https://mydomain.com/'
+
+    menuBuilder = new TestableMainMenuBuilder(runtimeConfig, ability, organizationProfile, accessProfile)
+})
+
+describe('getMenuName', () => {
+    test('validate name', () => {
+        expect(menuBuilder.getMenuName()).toEqual("Main")
+    })
+})
+
+describe('build', () => {
+    test('return all menus', () => {
+        menuBuilder.buildSubmenu = vi.fn((menuBuilder: typeof AbstractMenuBuilder): MenuGroup => {
+            return { label: 'foo' }
+        })
+
+        const result = menuBuilder.build() as MenuGroup
+
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(AccessMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(AgendaMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(EquipmentMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(EducationalMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(BillingMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(CommunicationMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(DonorsMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(MedalsMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(WebsiteAdminMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(CotisationsMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(StatsMenuBuilder)
+        expect(menuBuilder.buildSubmenu).toBeCalledWith(Admin2iosMenuBuilder)
+
+        expect(result.label).toEqual('main')
+        expect(result.icon).toEqual(undefined)
+        expect((result.children ?? []).length).toEqual(12)
+    })
+
+    test('return a single group', () => {
+        menuBuilder.buildSubmenu = vi.fn((menuBuilder: typeof AbstractMenuBuilder): MenuGroup | null => {
+            if (menuBuilder.menuName === 'Access') {
+                return { label: 'submenu', children: [
+                        {label: 'item1', type: MENU_LINK_TYPE.INTERNAL, active: true},
+                        {label: 'item2', type: MENU_LINK_TYPE.INTERNAL, active: true},
+                        {label: 'item3', type: MENU_LINK_TYPE.INTERNAL, active: true}
+                    ] }
+            }
+            return  null
+        })
+
+        const result = menuBuilder.build() as MenuGroup
+
+        expect(result.label).toEqual('submenu')
+        expect((result.children ?? []).length).toEqual(3)
+    })
+
+    test('return null', () => {
+        menuBuilder.buildSubmenu = vi.fn((menuBuilder: typeof AbstractMenuBuilder): MenuGroup | null => {
+            return  null
+        })
+
+        const result = menuBuilder.build() as MenuGroup
+
+        expect(result).toEqual(null)
+    })
+})

+ 153 - 2
tests/units/services/sse/sseSource.test.ts

@@ -1,22 +1,173 @@
 import { describe, test, it, expect } from 'vitest'
+import SseSource from "~/services/sse/sseSource";
+import {EventSourcePolyfill} from "event-source-polyfill";
 
+class TestableSseSource extends SseSource {
+    public getUrl() { return this.url }
+    public getOnOpen() { return this.onOpen }
+    public getOnMessage() { return this.onMessage }
+    public getOnClose() { return this.onClose }
+    public getWithCredentials() { return this.withCredentials }
+
+    public createEventSource(url: string, withCredentials: boolean): EventSourcePolyfill {
+        return super.createEventSource(url, withCredentials)
+    }
+
+    public setEventSource(eventSource: EventSourcePolyfill) {
+        this.eventSource = eventSource
+    }
+}
+
+let mercureUrl: string
+let topic: string
+let onOpen: () => any
+let onMessage: (data: Array<any>) => any
+let onClose: () => any
+let sseSource: TestableSseSource
 
 beforeEach(() => {
-    
+    mercureUrl = 'https://my.mercure.com'
+    topic = 'mytopic'
+
+    onOpen = () => 'opened'
+    onMessage = (data: Array<any>) => 'message'
+    onClose = () => 'closed'
+
+    sseSource = new TestableSseSource(mercureUrl, topic, onOpen, onMessage, onClose, false)
+})
+
+afterEach(() => {
+    vi.restoreAllMocks()
+})
+
+describe('test constructor', () => {
+    test('with all params', () => {
+        expect(sseSource.getUrl().toString()).toEqual('https://my.mercure.com/?topic=mytopic')
+        expect(sseSource.getOnOpen()).toEqual(onOpen)
+        expect(sseSource.getOnMessage()).toEqual(onMessage)
+        expect(sseSource.getOnClose()).toEqual(onClose)
+        expect(sseSource.getWithCredentials()).toEqual(false)
+    })
 })
 
 describe('createEventSource', () => {
+    test('simple call', () => {
+        const eventSource = sseSource.createEventSource(mercureUrl, false)
 
+        expect(eventSource.readyState).toEqual(0)
+        expect(eventSource.url).toEqual(mercureUrl)
+        expect(eventSource.withCredentials).toEqual(false)
+    })
 })
 
 describe('isConnected', () => {
-
+    test('no event source', () => {
+        expect(sseSource.isConnected()).toEqual(false)
+    })
+    test('got an event source, but it is not open', () => {
+        const eventSource = sseSource.createEventSource(mercureUrl, true)
+        sseSource.setEventSource(eventSource)
+        expect(sseSource.isConnected()).toEqual(false)
+    })
+    test('got an open event source', () => {
+        // @ts-ignore
+        const eventSource = vi.fn() as EventSourcePolyfill
+        // @ts-ignore
+        // noinspection JSConstantReassignment
+        eventSource.readyState = EventSourcePolyfill.OPEN
+        sseSource.setEventSource(eventSource)
+        expect(sseSource.isConnected()).toEqual(true)
+    })
 })
 
 describe('subscribe', () => {
+    test('already connected', () => {
+        sseSource.isConnected = vi.fn(() => true)
+        expect(() => sseSource.subscribe()).toThrowError("SSE - Already subscribed to this event source")
+    })
+    test('is server side', () => {
+        process.server = true
+        expect(() => sseSource.subscribe()).toThrowError("SSE - Cannot subscribe on server side")
+        process.server = false
+    })
+    test('successful subscription', () => {
+
+        onOpen = vi.fn(() => null)
+        onMessage = vi.fn((data: Array<any>) => null)
+
+        sseSource = new TestableSseSource(mercureUrl, topic, onOpen, onMessage, onClose)
+
+        const dummyEventSource = new EventSourcePolyfill('https://my.mercure.com', { withCredentials: true })
+
+        sseSource.createEventSource = vi.fn((url: string, withCredentials: boolean) => {
+            return dummyEventSource
+        })
 
+        console.log = vi.fn()
+        console.error = vi.fn()
+
+        sseSource.subscribe()
+        expect(sseSource.createEventSource).toHaveBeenCalled()
+
+        // @ts-ignore
+        dummyEventSource.onopen()
+        expect(onOpen).toHaveBeenCalled()
+        expect(console.log).toHaveBeenCalledWith('SSE - Listening for events...')
+
+        // @ts-ignore
+        dummyEventSource.onmessage({ data: '1' })
+        expect(onMessage).toHaveBeenCalledWith(1)
+
+        // @ts-ignore
+        dummyEventSource.onerror()
+        expect(console.error).toHaveBeenCalledWith('SSE - An error happened')
+    })
 })
 
 describe('unsubscribe', () => {
+    test('if no event source, does nothing', () => {
+        onClose = vi.fn(() => null)
+        sseSource = new TestableSseSource(mercureUrl, topic, onOpen, onMessage, onClose)
+
+        sseSource.unsubscribe()
+
+        expect(onClose).toHaveBeenCalledTimes(0)
+    })
+
+    test('if event source is not opened, does nothing', () => {
+        onClose = vi.fn(() => null)
+        sseSource = new TestableSseSource(mercureUrl, topic, onOpen, onMessage, onClose)
+
+        // @ts-ignore
+        const eventSource = vi.fn() as EventSourcePolyfill
+        // @ts-ignore
+        // noinspection JSConstantReassignment
+        eventSource.readyState = EventSourcePolyfill.CLOSED
+        sseSource.setEventSource(eventSource)
+
+        sseSource.unsubscribe()
+
+        expect(onClose).toHaveBeenCalledTimes(0)
+    })
+
+    test('has an open subscription', () => {
+        onClose = vi.fn(() => null)
+        sseSource = new TestableSseSource(mercureUrl, topic, onOpen, onMessage, onClose)
+
+        // @ts-ignore
+        const eventSource = vi.fn() as EventSourcePolyfill
+        // @ts-ignore
+        // noinspection JSConstantReassignment
+        eventSource.readyState = EventSourcePolyfill.OPEN
+        eventSource.close = vi.fn(() => null)
+        sseSource.setEventSource(eventSource)
+
+        console.log = vi.fn()
+
+        sseSource.unsubscribe()
 
+        expect(eventSource.close).toHaveBeenCalled()
+        expect(onClose).toHaveBeenCalled()
+        expect(console.log).toHaveBeenCalledWith('SSE - Subscription closed')
+    })
 })