2021-06-19 02:57:45 +08:00
/ * *
* @jest - environment jsdom
* /
2021-08-28 06:37:27 +08:00
import fetchMock from "jest-fetch-mock"
2021-06-19 02:57:45 +08:00
import { JSDOM } from "jsdom"
2021-07-08 07:28:05 +08:00
import {
getNlsConfiguration ,
nlsConfigElementId ,
2021-07-10 06:42:16 +08:00
getConfigurationForLoader ,
2021-07-08 07:28:05 +08:00
setBodyBackgroundToThemeBackgroundColor ,
2021-07-10 06:42:16 +08:00
_createScriptURL ,
main ,
createBundlePath ,
2021-07-13 07:54:19 +08:00
} from "../../../../src/browser/pages/vscode"
2021-06-19 02:57:45 +08:00
describe ( "vscode" , ( ) = > {
describe ( "getNlsConfiguration" , ( ) = > {
2021-07-10 06:42:16 +08:00
let _document : Document
2021-06-19 02:57:45 +08:00
beforeEach ( ( ) = > {
2021-07-10 06:42:16 +08:00
// We use underscores to not confuse with global values
const { window : _window } = new JSDOM ( )
_document = _window . document
2021-08-28 06:37:27 +08:00
fetchMock . enableMocks ( )
} )
afterEach ( ( ) = > {
fetchMock . resetMocks ( )
2021-06-19 02:57:45 +08:00
} )
it ( "should throw an error if no nlsConfigElement" , ( ) = > {
const errorMsgPrefix = "[vscode]"
const errorMessage = ` ${ errorMsgPrefix } Could not parse NLS configuration. Could not find nlsConfigElement with id: ${ nlsConfigElementId } `
expect ( ( ) = > {
2021-07-10 06:42:16 +08:00
getNlsConfiguration ( _document , "" )
2021-06-19 02:57:45 +08:00
} ) . toThrowError ( errorMessage )
} )
it ( "should throw an error if no nlsConfig" , ( ) = > {
2021-07-10 06:42:16 +08:00
const mockElement = _document . createElement ( "div" )
2021-06-19 02:57:45 +08:00
mockElement . setAttribute ( "id" , nlsConfigElementId )
2021-07-10 06:42:16 +08:00
_document . body . appendChild ( mockElement )
2021-06-19 02:57:45 +08:00
const errorMsgPrefix = "[vscode]"
const errorMessage = ` ${ errorMsgPrefix } Could not parse NLS configuration. Found nlsConfigElement but missing data-settings attribute. `
expect ( ( ) = > {
2021-07-10 06:42:16 +08:00
getNlsConfiguration ( _document , "" )
2021-06-19 02:57:45 +08:00
} ) . toThrowError ( errorMessage )
2021-07-10 06:42:16 +08:00
_document . body . removeChild ( mockElement )
2021-06-19 02:57:45 +08:00
} )
it ( "should return the correct configuration" , ( ) = > {
2021-07-10 06:42:16 +08:00
const mockElement = _document . createElement ( "div" )
2021-06-19 02:57:45 +08:00
const dataSettings = {
first : "Jane" ,
last : "Doe" ,
}
mockElement . setAttribute ( "id" , nlsConfigElementId )
mockElement . setAttribute ( "data-settings" , JSON . stringify ( dataSettings ) )
2021-07-10 06:42:16 +08:00
_document . body . appendChild ( mockElement )
const actual = getNlsConfiguration ( _document , "" )
2021-06-19 02:57:45 +08:00
expect ( actual ) . toStrictEqual ( dataSettings )
2021-07-10 06:42:16 +08:00
_document . body . removeChild ( mockElement )
} )
2021-08-28 06:37:27 +08:00
it ( "should return and have a loadBundle property if _resolvedLangaugePackCoreLocation" , async ( ) = > {
2021-07-10 06:42:16 +08:00
const mockElement = _document . createElement ( "div" )
const dataSettings = {
locale : "en" ,
availableLanguages : [ "en" , "de" ] ,
_resolvedLanguagePackCoreLocation : "./" ,
}
mockElement . setAttribute ( "id" , nlsConfigElementId )
mockElement . setAttribute ( "data-settings" , JSON . stringify ( dataSettings ) )
_document . body . appendChild ( mockElement )
const nlsConfig = getNlsConfiguration ( _document , "" )
expect ( nlsConfig . _resolvedLanguagePackCoreLocation ) . not . toBe ( undefined )
expect ( nlsConfig . loadBundle ) . not . toBe ( undefined )
2021-08-28 06:37:27 +08:00
const mockCallbackFn = jest . fn ( ( _ , bundle ) = > {
return bundle
} )
fetchMock . mockOnce ( JSON . stringify ( { key : "hello world" } ) )
// Ensure that load bundle works as expected
// by mocking the fetch response and checking that the callback
// had the expected value
await nlsConfig . loadBundle ( "hello" , "en" , mockCallbackFn )
expect ( mockCallbackFn ) . toHaveBeenCalledTimes ( 1 )
expect ( mockCallbackFn ) . toHaveBeenCalledWith ( undefined , { key : "hello world" } )
// Call it again to ensure it loads from the cache
// it should return the same value
await nlsConfig . loadBundle ( "hello" , "en" , mockCallbackFn )
expect ( mockCallbackFn ) . toHaveBeenCalledTimes ( 2 )
expect ( mockCallbackFn ) . toHaveBeenCalledWith ( undefined , { key : "hello world" } )
fetchMock . mockReject ( new Error ( "fake error message" ) )
const mockCallbackFn2 = jest . fn ( ( error ) = > error )
// Call it for a different bundle and mock a failed fetch call
// to ensure we get the expected error
const error = await nlsConfig . loadBundle ( "goodbye" , "es" , mockCallbackFn2 )
expect ( error . message ) . toEqual ( "fake error message" )
// Clean up
2021-07-10 06:42:16 +08:00
_document . body . removeChild ( mockElement )
} )
} )
describe ( "createBundlePath" , ( ) = > {
it ( "should return the correct path" , ( ) = > {
const _resolvedLangaugePackCoreLocation = "./languages"
const bundle = "/bundle.js"
const expected = "./languages/!bundle.js.nls.json"
const actual = createBundlePath ( _resolvedLangaugePackCoreLocation , bundle )
expect ( actual ) . toBe ( expected )
2021-06-19 02:57:45 +08:00
} )
2021-08-28 06:37:27 +08:00
it ( "should return the correct path (even if _resolvedLangaugePackCoreLocation is undefined)" , ( ) = > {
const _resolvedLangaugePackCoreLocation = undefined
const bundle = "/bundle.js"
const expected = "/!bundle.js.nls.json"
const actual = createBundlePath ( _resolvedLangaugePackCoreLocation , bundle )
expect ( actual ) . toBe ( expected )
} )
2021-06-19 02:57:45 +08:00
} )
2021-07-08 07:28:05 +08:00
describe ( "setBodyBackgroundToThemeBackgroundColor" , ( ) = > {
2021-07-10 06:42:16 +08:00
let _document : Document
let _localStorage : Storage
2021-07-08 07:28:05 +08:00
beforeEach ( ( ) = > {
// We need to set the url in the JSDOM constructor
// to prevent this error "SecurityError: localStorage is not available for opaque origins"
// See: https://github.com/jsdom/jsdom/issues/2304#issuecomment-622314949
2021-07-10 06:42:16 +08:00
const { window : _window } = new JSDOM ( "" , { url : "http://localhost" } )
_document = _window . document
_localStorage = _window . localStorage
2021-07-08 07:28:05 +08:00
} )
it ( "should return null" , ( ) = > {
const test = {
colorMap : {
[ ` editor.background ` ] : "#ff3270" ,
} ,
}
2021-07-10 06:42:16 +08:00
_localStorage . setItem ( "colorThemeData" , JSON . stringify ( test ) )
2021-07-08 07:28:05 +08:00
2021-07-10 06:42:16 +08:00
expect ( setBodyBackgroundToThemeBackgroundColor ( _document , _localStorage ) ) . toBeNull ( )
2021-07-08 07:28:05 +08:00
2021-07-10 06:42:16 +08:00
_localStorage . removeItem ( "colorThemeData" )
2021-07-08 07:28:05 +08:00
} )
it ( "should throw an error if it can't find colorThemeData in localStorage" , ( ) = > {
const errorMsgPrefix = "[vscode]"
const errorMessage = ` ${ errorMsgPrefix } Could not set body background to theme background color. Could not find colorThemeData in localStorage. `
expect ( ( ) = > {
2021-07-10 06:42:16 +08:00
setBodyBackgroundToThemeBackgroundColor ( _document , _localStorage )
2021-07-08 07:28:05 +08:00
} ) . toThrowError ( errorMessage )
} )
it ( "should throw an error if there is an error parsing colorThemeData from localStorage" , ( ) = > {
const errorMsgPrefix = "[vscode]"
const errorMessage = ` ${ errorMsgPrefix } Could not set body background to theme background color. Could not parse colorThemeData from localStorage. `
2021-07-10 06:42:16 +08:00
_localStorage . setItem (
2021-07-08 07:28:05 +08:00
"colorThemeData" ,
'{"id":"vs-dark max-SS-Cyberpunk-themes-cyberpunk-umbra-color-theme-json","label":"Activate UMBRA protocol","settingsId":"Activate "errorForeground":"#ff3270","foreground":"#ffffff","sideBarTitle.foreground":"#bbbbbb"},"watch\\":::false}' ,
)
expect ( ( ) = > {
2021-07-10 06:42:16 +08:00
setBodyBackgroundToThemeBackgroundColor ( _document , _localStorage )
2021-07-08 07:28:05 +08:00
} ) . toThrowError ( errorMessage )
localStorage . removeItem ( "colorThemeData" )
} )
it ( "should throw an error if there is no colorMap property" , ( ) = > {
const errorMsgPrefix = "[vscode]"
const errorMessage = ` ${ errorMsgPrefix } Could not set body background to theme background color. colorThemeData is missing colorMap. `
const test = {
id : "hey-joe" ,
}
2021-07-10 06:42:16 +08:00
_localStorage . setItem ( "colorThemeData" , JSON . stringify ( test ) )
2021-07-08 07:28:05 +08:00
expect ( ( ) = > {
2021-07-10 06:42:16 +08:00
setBodyBackgroundToThemeBackgroundColor ( _document , _localStorage )
2021-07-08 07:28:05 +08:00
} ) . toThrowError ( errorMessage )
2021-07-10 06:42:16 +08:00
_localStorage . removeItem ( "colorThemeData" )
2021-07-08 07:28:05 +08:00
} )
it ( "should throw an error if there is no editor.background color" , ( ) = > {
const errorMsgPrefix = "[vscode]"
const errorMessage = ` ${ errorMsgPrefix } Could not set body background to theme background color. colorThemeData.colorMap["editor.background"] is undefined. `
const test = {
id : "hey-joe" ,
colorMap : {
editor : "#fff" ,
} ,
}
2021-07-10 06:42:16 +08:00
_localStorage . setItem ( "colorThemeData" , JSON . stringify ( test ) )
2021-07-08 07:28:05 +08:00
expect ( ( ) = > {
2021-07-10 06:42:16 +08:00
setBodyBackgroundToThemeBackgroundColor ( _document , _localStorage )
2021-07-08 07:28:05 +08:00
} ) . toThrowError ( errorMessage )
2021-07-10 06:42:16 +08:00
_localStorage . removeItem ( "colorThemeData" )
2021-07-08 07:28:05 +08:00
} )
it ( "should set the body background to the editor background color" , ( ) = > {
const test = {
colorMap : {
[ ` editor.background ` ] : "#ff3270" ,
} ,
}
2021-07-10 06:42:16 +08:00
_localStorage . setItem ( "colorThemeData" , JSON . stringify ( test ) )
2021-07-08 07:28:05 +08:00
2021-07-10 06:42:16 +08:00
setBodyBackgroundToThemeBackgroundColor ( _document , _localStorage )
2021-07-08 07:28:05 +08:00
// When the body.style.backgroundColor is set using hex
// it is converted to rgb
// which is why we use that in the assertion
2021-07-10 06:42:16 +08:00
expect ( _document . body . style . backgroundColor ) . toBe ( "rgb(255, 50, 112)" )
2021-07-08 07:28:05 +08:00
2021-07-10 06:42:16 +08:00
_localStorage . removeItem ( "colorThemeData" )
} )
} )
describe ( "getConfigurationForLoader" , ( ) = > {
let _window : Window
beforeEach ( ( ) = > {
const { window : __window } = new JSDOM ( )
// @ts-expect-error the Window from JSDOM is not exactly the same as Window
// so we expect an error here
_window = __window
} )
it ( "should return a loader object (with undefined trustedTypesPolicy)" , ( ) = > {
const options = {
base : "." ,
csStaticBase : "/" ,
logLevel : 1 ,
}
const nlsConfig = {
first : "Jane" ,
last : "Doe" ,
locale : "en" ,
availableLanguages : { } ,
}
const loader = getConfigurationForLoader ( {
options ,
_window ,
nlsConfig : nlsConfig ,
} )
expect ( loader ) . toStrictEqual ( {
baseUrl : "http://localhost//lib/vscode/out" ,
paths : {
"iconv-lite-umd" : "../node_modules/iconv-lite-umd/lib/iconv-lite-umd.js" ,
jschardet : "../node_modules/jschardet/dist/jschardet.min.js" ,
"tas-client-umd" : "../node_modules/tas-client-umd/lib/tas-client-umd.js" ,
"vscode-oniguruma" : "../node_modules/vscode-oniguruma/release/main" ,
"vscode-textmate" : "../node_modules/vscode-textmate/release/main" ,
xterm : "../node_modules/xterm/lib/xterm.js" ,
"xterm-addon-search" : "../node_modules/xterm-addon-search/lib/xterm-addon-search.js" ,
"xterm-addon-unicode11" : "../node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js" ,
"xterm-addon-webgl" : "../node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js" ,
} ,
recordStats : true ,
trustedTypesPolicy : undefined ,
"vs/nls" : {
availableLanguages : { } ,
first : "Jane" ,
last : "Doe" ,
locale : "en" ,
} ,
} )
} )
it ( "should return a loader object with trustedTypesPolicy" , ( ) = > {
interface PolicyOptions {
createScriptUrl : ( url : string ) = > string
}
function mockCreatePolicy ( policyName : string , options : PolicyOptions ) {
return {
name : policyName ,
. . . options ,
}
}
const mockFn = jest . fn ( mockCreatePolicy )
// @ts-expect-error we are adding a custom property to window
_window . trustedTypes = {
createPolicy : mockFn ,
}
const options = {
base : "/" ,
csStaticBase : "/" ,
logLevel : 1 ,
}
const nlsConfig = {
first : "Jane" ,
last : "Doe" ,
locale : "en" ,
availableLanguages : { } ,
}
const loader = getConfigurationForLoader ( {
options ,
_window ,
nlsConfig : nlsConfig ,
} )
expect ( loader . trustedTypesPolicy ) . not . toBe ( undefined )
expect ( loader . trustedTypesPolicy . name ) . toBe ( "amdLoader" )
2021-08-28 06:37:27 +08:00
// Check that we can actually create a script URL
// using the createScriptURL on the loader object
const scriptUrl = loader . trustedTypesPolicy . createScriptURL ( "http://localhost/foo.js" )
expect ( scriptUrl ) . toBe ( "http://localhost/foo.js" )
2021-07-10 06:42:16 +08:00
} )
} )
describe ( "_createScriptURL" , ( ) = > {
it ( "should return the correct url" , ( ) = > {
const url = _createScriptURL ( "localhost/foo/bar.js" , "localhost" )
expect ( url ) . toBe ( "localhost/foo/bar.js" )
} )
it ( "should throw if the value doesn't start with the origin" , ( ) = > {
expect ( ( ) = > {
_createScriptURL ( "localhost/foo/bar.js" , "coder.com" )
} ) . toThrow ( "Invalid script url: localhost/foo/bar.js" )
} )
} )
describe ( "main" , ( ) = > {
let _window : Window
let _document : Document
let _localStorage : Storage
beforeEach ( ( ) = > {
// We need to set the url in the JSDOM constructor
// to prevent this error "SecurityError: localStorage is not available for opaque origins"
// See: https://github.com/jsdom/jsdom/issues/2304#issuecomment-62231494
const { window : __window } = new JSDOM ( "" , { url : "http://localhost" } )
// @ts-expect-error the Window from JSDOM is not exactly the same as Window
// so we expect an error here
_window = __window
_document = __window . document
_localStorage = __window . localStorage
const mockElement = _document . createElement ( "div" )
const dataSettings = {
first : "Jane" ,
last : "Doe" ,
}
mockElement . setAttribute ( "id" , nlsConfigElementId )
mockElement . setAttribute ( "data-settings" , JSON . stringify ( dataSettings ) )
_document . body . appendChild ( mockElement )
const test = {
colorMap : {
[ ` editor.background ` ] : "#ff3270" ,
} ,
}
_localStorage . setItem ( "colorThemeData" , JSON . stringify ( test ) )
} )
afterEach ( ( ) = > {
_localStorage . removeItem ( "colorThemeData" )
} )
it ( "should throw if document is missing" , ( ) = > {
expect ( ( ) = > {
main ( undefined , _window , _localStorage )
} ) . toThrow ( "document is undefined." )
} )
it ( "should throw if window is missing" , ( ) = > {
expect ( ( ) = > {
main ( _document , undefined , _localStorage )
} ) . toThrow ( "window is undefined." )
} )
it ( "should throw if localStorage is missing" , ( ) = > {
expect ( ( ) = > {
main ( _document , _window , undefined )
} ) . toThrow ( "localStorage is undefined." )
} )
it ( "should add loader to self.require" , ( ) = > {
main ( _document , _window , _localStorage )
expect ( Object . prototype . hasOwnProperty . call ( self , "require" ) ) . toBe ( true )
} )
it ( "should not throw in browser context" , ( ) = > {
// Assuming we call it in a normal browser context
// where everything is defined
expect ( ( ) = > {
main ( _document , _window , _localStorage )
} ) . not . toThrow ( )
2021-07-08 07:28:05 +08:00
} )
} )
2021-06-19 02:57:45 +08:00
} )