-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: iss 398/viv 224 core declarative config (#416)
* issue #398: initial commit * issue #398: tests to start with :) * issue #398: added karma HTML to perform tests within iframes * issue #398: fixing tests stuff * issue #398: fixing one of the tests - implemented * issue #398: implemented theme context configuration * issue #398: fixing Sonar remarks * issue #398: added some tests * issue #398: added actualy CSS variables verification to the encapsulated tests * issue #398: fixing CR of Yinon Co-authored-by: yinon <[email protected]>
- Loading branch information
Showing
8 changed files
with
311 additions
and
93 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,95 @@ | ||
import configurer, { Configuration } from './vvd-configurer.js'; | ||
import fonts from '@vonage/vvd-fonts/vvd-fonts.js'; | ||
import schemeService from '@vonage/vvd-scheme'; | ||
import schemeService, { SchemeOption } from '@vonage/vvd-scheme'; | ||
|
||
let coreAutoInitDone: Promise<Array<unknown>>; | ||
if (configurer.initialConfiguration.autoInit) { | ||
coreAutoInitDone = applyConfiguration(configurer.initialConfiguration); | ||
const VVD_CONTEXT_ATTRIBUTE = 'data-vvd-context', | ||
NONE_INIT_VALUE = 'none', | ||
VALID_CONFIGURATION_KEYS = ['scheme']; | ||
|
||
export interface Configuration { | ||
scheme?: SchemeOption; | ||
} | ||
|
||
interface InitialConfiguration extends Configuration { | ||
autoInit: boolean; | ||
} | ||
|
||
let coreAutoInitDone: Promise<Record<string, unknown>>; | ||
const initialConfiguration = _buildConfiguration(); | ||
if (initialConfiguration.autoInit) { | ||
coreAutoInitDone = _applyConfiguration(initialConfiguration); | ||
} else { | ||
coreAutoInitDone = Promise.reject('auto-init unavailable when "none" used'); | ||
coreAutoInitDone = Promise.reject( | ||
`auto-init unavailable when '${NONE_INIT_VALUE}' used` | ||
); | ||
} | ||
|
||
export default Object.freeze({ | ||
set: applyConfiguration, | ||
set: safeApplyConfiguration, | ||
settled: coreAutoInitDone, | ||
}); | ||
|
||
async function applyConfiguration(configuration: Partial<Configuration>) { | ||
configurer.validateConfiguration(configuration); | ||
return init(configuration); | ||
async function safeApplyConfiguration( | ||
configuration: Partial<Configuration> | ||
): Promise<Record<string, unknown>> { | ||
_validateConfiguration(configuration); | ||
return _applyConfiguration(configuration); | ||
} | ||
|
||
async function init( | ||
async function _applyConfiguration( | ||
configuration: Partial<Configuration> | ||
): Promise<Array<unknown>> { | ||
return Promise.all([fonts.init(), schemeService.set(configuration.scheme)]); | ||
): Promise<Record<string, unknown>> { | ||
const allResults = await Promise.all([ | ||
fonts.init(), | ||
schemeService.set(configuration.scheme), | ||
]); | ||
return Object.freeze({ | ||
fonts: allResults[0], | ||
scheme: allResults[1], | ||
}); | ||
} | ||
|
||
function _buildConfiguration(): InitialConfiguration { | ||
const result: InitialConfiguration = { | ||
autoInit: true, | ||
}; | ||
const vvdContextAttrValue = document.documentElement.getAttribute( | ||
VVD_CONTEXT_ATTRIBUTE | ||
); | ||
if (vvdContextAttrValue === NONE_INIT_VALUE) { | ||
result.autoInit = false; | ||
} else if (vvdContextAttrValue) { | ||
const parsed = _parseVvdContextAttr(vvdContextAttrValue); | ||
Object.assign(result, parsed); | ||
} | ||
return result; | ||
} | ||
|
||
function _validateConfiguration(configuration: Partial<Configuration>) { | ||
const extraParams = Object.keys(configuration).filter( | ||
(k) => !VALID_CONFIGURATION_KEYS.includes(k) | ||
); | ||
|
||
if (extraParams.length) { | ||
console.warn( | ||
`unexpected configuration part/s '${extraParams}', only some of '${VALID_CONFIGURATION_KEYS}' expected` | ||
); | ||
} | ||
} | ||
|
||
function _parseVvdContextAttr(value: string): Record<string, unknown> { | ||
const tokens = value.trim().split(/\s+/); | ||
return tokens.reduce((result, token) => { | ||
if (/^theme:/.test(token)) { | ||
if (result.scheme) { | ||
console.error( | ||
`theme vivid context defined multiple times, only the first (${result.scheme}) will be effective` | ||
); | ||
} else { | ||
result.scheme = token.replace(/^theme:/, ''); | ||
} | ||
} else { | ||
console.warn(`unsupported token '${token}' in vivid context`); | ||
} | ||
return result; | ||
}, {} as Record<string, unknown>); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<title>Vivid - injectable isolated document as testing playground</title> | ||
<script type="module"> | ||
window.executeSetup = async () => { | ||
window.vvdCore = (await import('../vvd-core.js')).default; | ||
}; | ||
</script> | ||
</head> | ||
|
||
<body></body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,170 @@ | ||
import vvdCore from '../vvd-core.js'; | ||
import { | ||
randomAlpha, | ||
getFrameLoadedInjected, | ||
} from '../../../test/test-helpers.js'; | ||
import { | ||
assertBaseVarsMatch, | ||
PRINCIPAL_VARIABLES_FILTER, | ||
} from '../../../test/style-utils.js'; | ||
|
||
const CONTEXT_ATTR = 'data-vvd-context'; | ||
const CORE_SETUP_HTML_TAG = 'coreSetupTest'; | ||
const LIGHT = 'light'; | ||
const DARK = 'dark'; | ||
const NONE = 'none'; | ||
|
||
describe('vvd-core service', () => { | ||
it('verify basic core API', async () => { | ||
assert.isDefined(vvdCore, 'core service is defined'); | ||
assert.isObject(vvdCore, 'core service is a defaultly exported object'); | ||
assert.isFunction(vvdCore.set, 'core service has "set" API method'); | ||
assert.isDefined( | ||
vvdCore.settled, | ||
'core service has "settled" object (Promise)' | ||
); | ||
assert.isFunction( | ||
vvdCore.settled.then, | ||
'core service has "settled" object - ensure it is Promise' | ||
); | ||
describe('basic APIs', () => { | ||
it('is should init to default', async () => { | ||
const r = randomAlpha(); | ||
const vvdCore = (await import(`../vvd-core.js?t=${r}`)).default; | ||
assert.isDefined(vvdCore, 'core service is defined'); | ||
assert.isObject(vvdCore, 'core service is a defaultly exported object'); | ||
assert.isFunction(vvdCore.set, 'core service has "set" API method'); | ||
assert.isDefined( | ||
vvdCore.settled, | ||
'core service has "settled" object (Promise)' | ||
); | ||
assert.isFunction( | ||
vvdCore.settled.then, | ||
'core service has "settled" object - ensure it is Promise' | ||
); | ||
}); | ||
|
||
it('should init to none', async () => { | ||
document.documentElement.setAttribute(CONTEXT_ATTR, 'none'); | ||
const r = randomAlpha(); | ||
const vvdCore = (await import(`../vvd-core.js?t=${r}`)).default; | ||
document.documentElement.removeAttribute(CONTEXT_ATTR); | ||
try { | ||
await vvdCore.settled; | ||
} catch (e) { | ||
expect(e).exist; | ||
expect(e.includes('auto-init unavailable')).true; | ||
} | ||
}); | ||
|
||
it('should init to dark', async () => { | ||
document.documentElement.setAttribute(CONTEXT_ATTR, `theme:${DARK}`); | ||
const r = randomAlpha(); | ||
const vvdCore = (await import(`../vvd-core.js?t=${r}`)).default; | ||
document.documentElement.removeAttribute(CONTEXT_ATTR); | ||
const coreInitResult = await vvdCore.settled; | ||
|
||
assertInitResult(coreInitResult, DARK); | ||
}); | ||
|
||
it('should perform set', async () => { | ||
const r = randomAlpha(); | ||
const vvdCore = (await import(`../vvd-core.js?t=${r}`)).default; | ||
const coreInitResult = await vvdCore.set({ scheme: LIGHT }); | ||
|
||
assertInitResult(coreInitResult, LIGHT); | ||
}); | ||
|
||
it('should not fail on abnormal calls', async () => { | ||
document.documentElement.setAttribute( | ||
CONTEXT_ATTR, | ||
`illegal theme:${DARK} theme:${LIGHT}` | ||
); | ||
const r = randomAlpha(); | ||
const vvdCore = (await import(`../vvd-core.js?t=${r}`)).default; | ||
document.documentElement.removeAttribute(CONTEXT_ATTR); | ||
let coreInitResult = await vvdCore.settled; | ||
|
||
assertInitResult(coreInitResult, DARK); | ||
|
||
coreInitResult = await vvdCore.set({ | ||
scheme: DARK, | ||
illegal: { some: null }, | ||
}); | ||
assertInitResult(coreInitResult, DARK); | ||
}); | ||
}); | ||
|
||
it('should perform and auto-init to default when no data-vvd-context provided', async () => { | ||
const vvdCoreDedicated = (await import('../vvd-core.js')).default; | ||
assert.isDefined(vvdCoreDedicated.settled); | ||
const readyResult = await vvdCoreDedicated.settled; | ||
assert.isArray(readyResult); | ||
readyResult.forEach((r) => { | ||
assert.isObject(r); | ||
describe('switch flows in encapsulated environment and assert variables set', () => { | ||
it('should perform auto-init to default when no data-vvd-context provided', async () => { | ||
await getFrameLoadedInjected(CORE_SETUP_HTML_TAG, async (iframe) => { | ||
const iframeWindow = iframe.contentWindow; | ||
await iframeWindow.executeSetup(); | ||
const coreInitResult = await iframeWindow.vvdCore.settled; | ||
|
||
assertInitResult(coreInitResult, LIGHT); | ||
assertBaseVarsMatch( | ||
LIGHT, | ||
PRINCIPAL_VARIABLES_FILTER, | ||
iframe.contentDocument.body | ||
); | ||
}); | ||
}); | ||
|
||
it('should perform auto-init to a value in data-vvd-context, when provided', async () => { | ||
const vvdContextTheme = DARK; | ||
await getFrameLoadedInjected(CORE_SETUP_HTML_TAG, async (iframe) => { | ||
iframe.contentDocument.documentElement.setAttribute( | ||
CONTEXT_ATTR, | ||
`theme:${vvdContextTheme}` | ||
); | ||
|
||
const iframeWindow = iframe.contentWindow; | ||
await iframeWindow.executeSetup(); | ||
const coreInitResult = await iframeWindow.vvdCore.settled; | ||
|
||
assertInitResult(coreInitResult, vvdContextTheme); | ||
assertBaseVarsMatch( | ||
vvdContextTheme, | ||
PRINCIPAL_VARIABLES_FILTER, | ||
iframe.contentDocument.body | ||
); | ||
}); | ||
}); | ||
|
||
it('should NOT perform auto-init when data-vvd-context is "none"', async () => { | ||
const vvdContextNone = NONE; | ||
await getFrameLoadedInjected(CORE_SETUP_HTML_TAG, async (iframe) => { | ||
iframe.contentDocument.documentElement.setAttribute( | ||
CONTEXT_ATTR, | ||
vvdContextNone | ||
); | ||
|
||
const iframeWindow = iframe.contentWindow; | ||
await iframeWindow.executeSetup(); | ||
|
||
try { | ||
await iframeWindow.vvdCore.settled; | ||
} catch (e) { | ||
expect(e).exist; | ||
expect(e.includes('auto-init unavailable')).true; | ||
} | ||
}); | ||
}); | ||
|
||
it('should perform init to a first value in data-vvd-context, when many provided', async () => { | ||
const vvdContextTheme = LIGHT; | ||
await getFrameLoadedInjected(CORE_SETUP_HTML_TAG, async (iframe) => { | ||
iframe.contentDocument.documentElement.setAttribute( | ||
CONTEXT_ATTR, | ||
`theme:${vvdContextTheme} theme:${DARK}` | ||
); | ||
|
||
const iframeWindow = iframe.contentWindow; | ||
await iframeWindow.executeSetup(); | ||
const coreInitResult = await iframeWindow.vvdCore.settled; | ||
|
||
assertInitResult(coreInitResult, vvdContextTheme); | ||
assertBaseVarsMatch( | ||
vvdContextTheme, | ||
PRINCIPAL_VARIABLES_FILTER, | ||
iframe.contentDocument.body | ||
); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
function assertInitResult(tested, expectedScheme) { | ||
expect(tested).exist; | ||
expect(tested.scheme).exist; | ||
expect(tested.scheme.option).equal(expectedScheme); | ||
expect(tested.scheme.scheme).equal(expectedScheme); | ||
} |
Oops, something went wrong.