UNPKG

@lightningjs/sdk

Version:

The Lightning-SDK helps you build great Lightning-based TV apps!

515 lines (444 loc) 15 kB
/* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * * Copyright 2022 Metrological * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { expectType, expectAssignable, expectNotAssignable, expectDeprecated, expectNotDeprecated } from 'tsd'; import { Router, Lightning } from '../../index.js' import Request from '../../src/Router/model/Request.js'; function Router_Config_Tests() { /// Basic expectAssignable<Router.Config>({ root: 'splash', routes: [ { path: 'splash', component: {} as Router.PageConstructor }, {} as Router.RouteDefinition, {} as Router.RouteDefinition ] }); /// `root` and `routes` are required! expectNotAssignable<Router.Config>({ root: 'splash', }); expectNotAssignable<Router.Config>({ routes: [], }); /// `root` and `routes` type sanity check expectNotAssignable<Router.Config>({ root: 123, // Must be a string! routes: [ {} as Router.RouteDefinition ] }); expectNotAssignable<Router.Config>({ root: 'abc', routes: [ {} // Must be RouteDefinition! ] }); /// `boot` and `root` as promise returning callbacks expectAssignable<Router.Config>({ root: () => { return Promise.resolve('splash') }, boot: (qs) => { /// `qs` infers to param type expectType<Record<string, string | undefined>>(qs); return Promise.resolve(); }, routes: [] }); /// Supports custom `appInstance` any component expectAssignable<Router.Config>({ root: 'splash', routes: [], appInstance: {} as Lightning.Component }); /// `updateHash` expectAssignable<Router.Config>({ root: 'splash', routes: [], updateHash: false }); /// `beforeEachRoute` expectAssignable<Router.Config>({ root: 'splash', routes: [], beforeEachRoute: async (from, to) => { expectType<string>(from); expectType<Request>(to); return true; } }); /// `afterEachRoute` expectAssignable<Router.Config>({ root: 'splash', routes: [], afterEachRoute: (request) => { expectType<Request>(request); return true; } }); /// `bootComponent` deprecated const routeConfig = {} as Router.Config; expectDeprecated(routeConfig.bootComponent); } function Router_startRouter_Tests() { const routeConfig = {} as Router.Config; /// Supports just passing a `config` expectType<void>(Router.startRouter(routeConfig)); // @ts-expect-error `config` can't be a number Router.startRouter(123); /// Supports passing a `config` and an app `instance` expectType<void>(Router.startRouter(routeConfig, {} as Lightning.Component)); // @ts-expect-error `instance` can't be a number Router.startRouter(routeConfig, 123); } function Router_RouteDefinition_Tests() { class MyPage extends Lightning.Component<Lightning.Component.TemplateSpecLoose, { IsPage: true } & Lightning.Component.TypeConfig> {} /// Simple RouteDefintions can be assigned expectAssignable<Router.RouteDefinition>({ path: 'myPath/:param1/:param2', component: MyPage }); /// Non-Pages cannot be assigned expectNotAssignable<Router.RouteDefinition>({ path: 'myPath/:param1/:param2', component: Lightning.components.ListComponent }); /// Non-Pages can be assigned with `any` expectAssignable<Router.RouteDefinition>({ path: 'myPath/:param1/:param2', component: Lightning.components.ListComponent as any }); /// Can assign `on` expectAssignable<Router.RouteDefinition>({ path: 'myPath/:param1/:param2', component: MyPage, async on(page, { param1, param2 }) { expectType<Router.PageInstance>(page); expectAssignable<MyPage>(page); expectType<string | undefined>(param1); expectType<string | undefined>(param2); } }); /// Can assign `before` expectAssignable<Router.RouteDefinition>({ path: 'myPath/:param1/:param2', component: MyPage, async before(page, { param1, param2 }) { expectType<Router.PageInstance>(page); expectAssignable<MyPage>(page); expectType<string | undefined>(param1); expectType<string | undefined>(param2); } }); /// Can assign `after` expectAssignable<Router.RouteDefinition>({ path: 'myPath/:param1/:param2', component: MyPage, async after(page, { param1, param2 }) { expectType<Router.PageInstance>(page); expectAssignable<MyPage>(page); expectType<string | undefined>(param1); expectType<string | undefined>(param2); } }); /// Can assign `cache` expectAssignable<Router.RouteDefinition>({ path: 'myPath/:param1/:param2', component: MyPage, cache: 1000 }); /// Can assign `widgets` expectAssignable<Router.RouteDefinition>({ path: 'myPath/:param1/:param2', component: MyPage, widgets: ['anotherwidget', 'myclockwidget', 'mymenuwidget', 'mywidget'] }); } function Router_navigate_Tests() { // Many examples taken from documentation: // https://lightningjs.io/docs/#/lightning-sdk-reference/plugins/router/navigation?id=router-navigation const namedNavigatePath: Router.NamedNavigationPath = {} as Router.NamedNavigationPath; const navigateArgs: Router.NavigateArgs = {} as Router.NavigateArgs; /// Can do simple navigate by string or named route expectType<void>( Router.navigate('player/1638') ); expectType<void>( Router.navigate(namedNavigatePath) ); /// Can do navigate with args expectType<void>( Router.navigate('player/1638', navigateArgs) ); expectType<void>( Router.navigate(namedNavigatePath, navigateArgs) ); /// Can do navigate and set 2nd param to false (to prevent history) expectType<void>( Router.navigate('player/1638', false) ); expectType<void>( Router.navigate(namedNavigatePath, false) ); /// Can do navigate and set 3rd param to false (to prevent history) expectType<void>( Router.navigate('player/1638', navigateArgs, false) ); expectType<void>( Router.navigate(namedNavigatePath, navigateArgs, false) ); } function Router_NamedNavigationPath_Tests() { /// `to` is the mimimum property required expectAssignable<Router.NamedNavigationPath>({ to: 'player', }); expectNotAssignable<Router.NamedNavigationPath>({}); /// Allow `params` to be specified expectAssignable<Router.NamedNavigationPath>({ to: 'player', params: { unknownProp1: 123, unknownProp2: 'abc', unknownProp3: true, } }); /// As well as `query` expectAssignable<Router.NamedNavigationPath>({ to: 'player', params: { unknownProp1: 123, unknownProp2: 'abc', unknownProp3: true, }, query: { unknownProp1: 123, unknownProp2: 'abc', unknownProp3: true, } }); /// `params` must be a Record<string, string | number | boolean> (if defined) expectNotAssignable<Router.NamedNavigationPath>({ to: 'player', params: { unknownProp4: {} // Not allowed } }); expectType<Record<string, string | number | boolean> | undefined>({} as Router.NamedNavigationPath['params']); /// `query` must be a Record<string, string | number | boolean> (if defined) expectNotAssignable<Router.NamedNavigationPath>({ to: 'player', query: { unknownProp4: {} // Not allowed } }); expectType<Record<string, string | number | boolean> | undefined>({} as Router.NamedNavigationPath['params']); } function Router_NavigateArgs_Tests() { /// NavigateArgs allows keepAlive, reload and anything else. expectAssignable<Router.NavigateArgs>({ keepAlive: true, reload: true, unknownProp1: 'abc', unknownProp2: 123, unknownProp3: false, unknownProp4: {} }); /// NavigateArgs: keepAlive and reload must be booleans expectType<boolean | undefined>({} as Router.NavigateArgs['keepAlive']); expectNotAssignable<Router.NavigateArgs>({ keepAlive: 'string', }); expectType<boolean | undefined>({} as Router.NavigateArgs['reload']); expectNotAssignable<Router.NavigateArgs>({ reload: 'string', }); } function Router_resume_Tests() { /// Should return void with no params expectType<void>(Router.resume()); /// Should error if there are any params // @ts-expect-error Router.resume('abc'); } function Router_step_Tests() { /// `step` is an alias of `go` expectType<typeof Router.go>(Router.step); /// Should be deprecated expectDeprecated(Router.step); } function Router_go_Tests() { /// Works with no parameters expectType<void>(Router.go()); /// Works with numeric parameters expectType<void>(Router.go(-1)); expectType<void>(Router.go(-2)); expectType<void>(Router.go(-3)); /// Should not be deprecated expectNotDeprecated(Router.go); } function Router_back_Tests() { /// back() can be called with no parameters expectType<void>(Router.back()); } function Router_activePage_Tests() { /// Returns the correct value but is deprecated expectType<Lightning.Component | null>(Router.activePage()); /// Should be deprecated expectDeprecated(Router.activePage); } function Router_getActivePage_Tests() { /// Returns the correct value and is not deprecated expectType<Lightning.Component | null>(Router.getActivePage()); /// Should not be deprecated expectNotDeprecated(Router.getActivePage); } function Router_getActiveRoute_Tests() { /// Returns the correct value and is not deprecated expectType<string | undefined>(Router.getActiveRoute()); } function Router_getActiveHash_Tests() { /// Returns the correct value and is not deprecated expectType<string | undefined>(Router.getActiveHash()); } declare module '../../index.js' { namespace Router { interface CustomWidgets { MyWidget: Lightning.Component AnotherWidget: Lightning.Component } } } function Router_focusWidget_Tests() { /// Works with augmented `CustomWidgets` expectType<void>(Router.focusWidget('MyWidget')); expectType<void>(Router.focusWidget('AnotherWidget')); /// Unknown widgets error (including lowercase forms of known widgets) // @ts-expect-error Router.focusWidget('mywidget'); // @ts-expect-error Router.focusWidget('UnknownWidget'); } function Router_getActiveWidget_Tests() { /// Returns the right value expectType<Lightning.Component | null>(Router.getActiveWidget()); /// Param sanity check: Should not accept a parameter // @ts-expect-error Router.getActiveWidget(123); } function Router_restoreFocus_Tests() { /// Should be an alias of focusPage expectType<typeof Router['restoreFocus']>(Router.focusPage); /// Should be deprecated expectDeprecated(Router.restoreFocus); } function Router_focusPage_Tests() { /// Should return void and accept no params expectType<void>(Router.focusPage()); /// Param sanity check: Should not accept a parameter // @ts-expect-error Router.getActiveWidget(123); /// Should not be deprecated expectNotDeprecated(Router.focusPage); } function Router_isNavigating_Tests() { /// Works as expected expectType<boolean>(Router.isNavigating()); } function Router_getHistory_Tests() { /// Should return an array of HistoryEntry[] expectType<Router.HistoryEntry[]>(Router.getHistory()); } function Router_setHistory_Tests() { /// Should return void, accepts an array of history objects expectType<void>(Router.setHistory([{ hash: '', state: {} }, { hash: '', state: {} }])); /// Should error if first param is not an array or if less than or more than one param is provided // @ts-expect-error Router.setHistory(123); // @ts-expect-error Router.setHistory(); // @ts-expect-error Router.setHistory([], 'abc'); } function Router_HistoryState_Tests() { type HistState = { myParam1: number, myParam2: string }; interface CustomTypeConfig extends Lightning.Component.TypeConfig { HistoryStateType: HistState } /// Should be typed as `Record<string, unknown> | null | undefined` if no params are passed to it expectType<Record<string, unknown> | null | undefined>({} as Router.HistoryState); /// Should extract the `HistoryStateType` if a TypeConfig is passed expectType<HistState | null | undefined>({} as Router.HistoryState<CustomTypeConfig>); /// Otherwise, it should just pass through any other object type passed in expectType<HistState | null | undefined>({} as Router.HistoryState<HistState>); } function Router_getHistoryState_Tests() { /// Should return HistoryState | null, and accept an optional `hash` string expectType<Router.HistoryState | null>(Router.getHistoryState()); expectType<Router.HistoryState | null>(Router.getHistoryState('abc')); /// Should error if first param isn't a string of if more than 1 param is provided // @ts-expect-error Router.getHistoryState(123); // @ts-expect-error Router.getHistoryState('abc', 123); } function Router_replaceHistoryState_Tests() { /// Should return void and work with no params, 1 param or 2 params expectType<void>(Router.replaceHistoryState()); expectType<void>(Router.replaceHistoryState({} as Router.HistoryState)); expectType<void>(Router.replaceHistoryState(null)); expectType<void>(Router.replaceHistoryState({} as Router.HistoryState, 'hash')); /// Should error if params are of wrong type or more than 2 // @ts-expect-error Router.replaceHistoryState(123); // @ts-expect-error Router.replaceHistoryState(null, 123); // @ts-expect-error Router.replaceHistoryState(null, 'hash', 'abc'); } function Router_getQueryStringParams_Tests() { /// Should return correct type and work with no params or 1 param expectType<Router.QueryParams | false>(Router.getQueryStringParams()); expectType<Router.QueryParams | false>(Router.getQueryStringParams('hash')); /// Should error if there are more than 1 param or type of param is incorrect // @ts-expect-error Router.getQueryStringParams(false); // @ts-expect-error Router.getQueryStringParams('hash', false); } function Router_reload_Tests() { /// Should return void with no params expectType<void>(Router.reload()); /// Should error if there are any params // @ts-expect-error Router.reload('abc'); } function Router_root_Tests() { /// Should return void with no params expectType<void>(Router.root()); /// Should error if there are any params // @ts-expect-error Router.root('abc'); }