@lightningjs/sdk
Version:
The Lightning-SDK helps you build great Lightning-based TV apps!
515 lines (444 loc) • 15 kB
text/typescript
/*
* 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');
}