Skip to content

Commit

Permalink
MWPW-135873 Compress the caas hash strings (#1401)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Sunil Kamat <107644736+sukamat@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 18, 2023
1 parent 8678727 commit 202c33f
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 27 deletions.
78 changes: 65 additions & 13 deletions libs/blocks/caas-config/caas-config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable compat/compat */
/* eslint-disable react-hooks/exhaustive-deps */
/* global ClipboardItem */
import {
Expand All @@ -13,10 +14,16 @@ import {
getConfig,
parseEncodedConfig,
loadStyle,
utf8ToB64,
} from '../../utils/utils.js';
import Accordion from '../../ui/controls/Accordion.js';
import { defaultState, initCaas, loadCaasFiles, loadCaasTags, loadStrings } from '../caas/utils.js';
import {
decodeCompressedString,
defaultState,
initCaas,
loadCaasFiles,
loadCaasTags,
loadStrings,
} from '../caas/utils.js';
import { Input as FormInput, Select as FormSelect } from '../../ui/controls/formControls.js';
import TagSelect from '../../ui/controls/TagSelector.js';
import MultiField from '../../ui/controls/MultiField.js';
Expand All @@ -36,13 +43,16 @@ const updateObj = (obj, defaultObj) => {

const isValidUuid = (id) => /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(id);

const getHashConfig = () => {
const getHashConfig = async () => {
const { hash } = window.location;
if (!hash) return null;
window.location.hash = '';

const encodedConfig = hash.startsWith('#') ? hash.substring(1) : hash;
return parseEncodedConfig(encodedConfig);
const config = encodedConfig.startsWith('~~')
? await decodeCompressedString(encodedConfig.substring(2))
: parseEncodedConfig(encodedConfig);
return config;
};

const caasFilesLoaded = loadCaasFiles();
Expand Down Expand Up @@ -700,14 +710,16 @@ const reducer = (state, action) => {
return { ...state, [action.prop]: action.value };
case 'RESET_STATE':
return cloneObj(defaultState);
case 'SET_STATE':
return cloneObj(action.value);
/* c8 ignore next 2 */
default:
return state;
}
};

const getInitialState = () => {
let state = getHashConfig();
const getInitialState = async () => {
let state = await getHashConfig();
// /* c8 ignore next 2 */
if (!state) {
const lsState = localStorage.getItem(LS_KEY);
Expand Down Expand Up @@ -741,6 +753,34 @@ const saveStateToLocalStorage = (state) => {
*/
const fgKeyReplacer = (key, value) => (key === 'fetchCardsFromFloodgateTree' ? undefined : value);

const getEncodedObject = async (obj, replacer = null) => {
if (!window.CompressionStream) {
await import('../../deps/compression-streams-pollyfill.js');
}

const objToStream = (data) => new Blob(
[JSON.stringify(data, replacer)],
{ type: 'text/plain' },
).stream();

const compressStream = async (stream) => new Response(
// eslint-disable-next-line no-undef
stream.pipeThrough(new CompressionStream('gzip')),
);

const responseToBuffer = async (res) => {
const blob = await res.blob();
return blob.arrayBuffer();
};

const b64encode = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)));

const stream = objToStream(obj);
const compressedResponse = await compressStream(stream);
const buffer = await responseToBuffer(compressedResponse);
return b64encode(buffer);
};

/* c8 ignore start */
const CopyBtn = () => {
const { state } = useContext(ConfiguratorContext);
Expand All @@ -756,22 +796,25 @@ const CopyBtn = () => {
}, 2000);
};

const getUrl = () => {
const getUrl = async () => {
const url = new URL(window.location.href);
url.search = '';
url.hash = utf8ToB64(JSON.stringify(state, fgKeyReplacer));
const hashStr = await getEncodedObject(state, fgKeyReplacer);
// starts with ~~ to differentiate from old hash format
url.hash = `~~${hashStr}`;
return url.href;
};

const copyConfig = () => {
setConfigUrl(getUrl());
const copyConfig = async () => {
const url = await getUrl();
setConfigUrl(url);
if (!navigator?.clipboard) {
setTempStatus(setIsError);
return;
}

const link = document.createElement('a');
link.href = getUrl();
link.href = url;
const dateStr = new Date().toLocaleString('us-EN', {
weekday: 'long',
year: 'numeric',
Expand All @@ -782,7 +825,7 @@ const CopyBtn = () => {
hour12: false,
});
const collectionName = state.collectionName ? `- ${state.collectionName} ` : '';
link.textContent = `Content as a Service ${collectionName}- ${dateStr}${state.doNotLazyLoad ? ' (no-lazy)' : ''}`;
link.textContent = `Content as a Service v2 ${collectionName}- ${dateStr}${state.doNotLazyLoad ? ' (no-lazy)' : ''}`;

const blob = new Blob([link.outerHTML], { type: 'text/html' });
const data = [new ClipboardItem({ [blob.type]: blob })];
Expand Down Expand Up @@ -899,7 +942,7 @@ const idOverlayMO = () => {
};

const Configurator = ({ rootEl }) => {
const [state, dispatch] = useReducer(reducer, getInitialState() || cloneObj(defaultState));
const [state, dispatch] = useReducer(reducer, {});
const [isCaasLoaded, setIsCaasLoaded] = useState(false);
const [strings, setStrings] = useState();
const [panels, setPanels] = useState([]);
Expand All @@ -919,6 +962,15 @@ const Configurator = ({ rootEl }) => {
});
}, []);

useEffect(() => {
const setInitialState = async () => {
const initialState = await getInitialState();
dispatch({ type: 'SET_STATE', value: initialState });
};

setInitialState();
}, []);

useEffect(() => {
if (state.showIds && !cardMutationObsv) {
/* c8 ignore next */
Expand Down
21 changes: 18 additions & 3 deletions libs/blocks/caas/caas.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { initCaas, loadCaasFiles, loadStrings, fgHeaderValue } from './utils.js';
import { parseEncodedConfig, createIntersectionObserver, getMetadata, getConfig, b64ToUtf8 } from '../../utils/utils.js';
import {
decodeCompressedString,
fgHeaderValue,
initCaas,
loadCaasFiles,
loadStrings,
} from './utils.js';
import {
b64ToUtf8,
createIntersectionObserver,
getConfig,
getMetadata,
parseEncodedConfig,
} from '../../utils/utils.js';

const ROOT_MARGIN = 1000;
const P_CAAS_AIO = b64ToUtf8('MTQyNTctY2hpbWVyYS5hZG9iZWlvcnVudGltZS5uZXQvYXBpL3YxL3dlYi9jaGltZXJhLTAuMC4xL2NvbGxlY3Rpb24=');
Expand All @@ -15,7 +27,10 @@ const getCaasStrings = (placeholderUrl) => new Promise((resolve) => {

const loadCaas = async (a) => {
const encodedConfig = a.href.split('#')[1];
const state = parseEncodedConfig(encodedConfig);
// ~~ indicates the new compressed string format
const state = encodedConfig.startsWith('~~')
? await decodeCompressedString(encodedConfig.substring(2))
: parseEncodedConfig(encodedConfig);

const [caasStrs] = await Promise.all([
getCaasStrings(state.placeholderUrl),
Expand Down
30 changes: 30 additions & 0 deletions libs/blocks/caas/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable compat/compat */
/* eslint-disable no-underscore-dangle */
import { loadScript, loadStyle, getConfig as pageConfigHelper } from '../../utils/utils.js';
import { fetchWithTimeout } from '../utils/utils.js';
Expand Down Expand Up @@ -56,6 +57,35 @@ export const loadStrings = async (
}
};

export const decodeCompressedString = async (txt) => {
if (!window.DecompressionStream) {
await import('../../deps/compression-streams-pollyfill.js');
}
const b64decode = (str) => {
const binaryStr = window.atob(str);
const bytes = new Uint8Array(new ArrayBuffer(binaryStr.length));
binaryStr?.split('')
.forEach((c, i) => (bytes[i] = c.charCodeAt(0)));
return bytes;
};

const b64toStream = (b64) => new Blob([b64decode(b64)], { type: 'text/plain' }).stream();

const decompressStream = async (stream) => new Response(
// eslint-disable-next-line no-undef
stream.pipeThrough(new DecompressionStream('gzip')),
);

const responseToJSON = async (response) => {
const blob = await response.blob();
return JSON.parse(await blob.text());
};

const stream = b64toStream(txt);
const resp = await decompressStream(stream);
return responseToJSON(resp);
};

export const loadCaasFiles = async () => {
const version = new URL(document.location.href)?.searchParams?.get('caasver') || 'stable';

Expand Down
1 change: 1 addition & 0 deletions libs/deps/compression-streams-pollyfill.js

Large diffs are not rendered by default.

45 changes: 38 additions & 7 deletions test/blocks/caas-config/caas-config.test.html
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,16 @@
const tagUrlInput = findByLabel('Tags Url', configPanelEl);
tagUrlInput.value = 'https://not.the.right.url/tags';
tagUrlInput.dispatchEvent(new Event('change'));
const errorEl = await waitForElement('.tool-error');
expect(errorEl).to.not.be.null;
expect(errorEl.textContent).to.be.equal('Unable to fetch tags, loading backup tags. Please check tags url in the Advanced Panel');

const toolErrorEl = await waitForElement('.tool-error');
expect(toolErrorEl).to.not.be.null;

// Due to a race condition, the error message may be one of two things
let correctErrorMsg = false;
if (toolErrorEl.textContent === 'Tags url is not defined in the Advanced Panel'
|| toolErrorEl.textContent === 'Unable to fetch tags, loading backup tags. Please check tags url in the Advanced Panel') {
correctErrorMsg = true;
}
expect(correctErrorMsg).to.be.true;
const expectedConfig = cloneObj(defaultConfig);
expect(config).to.eql(expectedConfig);
});
Expand Down Expand Up @@ -285,7 +291,24 @@
copyBtn.click();
await delay(50);
const copyTextArea = document.querySelector('.copy-text');
expect(copyTextArea.value.split('#')[1]).to.equal('eyJhZGRpdGlvbmFsUmVxdWVzdFBhcmFtcyI6W10sImFuYWx5dGljc0NvbGxlY3Rpb25OYW1lIjoiIiwiYW5hbHl0aWNzVHJhY2tJbXByZXNzaW9uIjpmYWxzZSwiYW5kTG9naWNUYWdzIjpbXSwiYXV0b0NvdW50cnlMYW5nIjpmYWxzZSwiYm9va21hcmtJY29uU2VsZWN0IjoiIiwiYm9va21hcmtJY29uVW5zZWxlY3QiOiIiLCJjYXJkU3R5bGUiOiJoYWxmLWhlaWdodCIsImNhcmRUaXRsZUFjY2Vzc2liaWxpdHlMZXZlbCI6NiwiY29sbGVjdGlvbkJ0blN0eWxlIjoicHJpbWFyeSIsImNvbGxlY3Rpb25OYW1lIjoiIiwiY29sbGVjdGlvblRpdGxlIjoiIiwiY29sbGVjdGlvblNpemUiOiIiLCJjb250YWluZXIiOiIxMjAwTWF4V2lkdGgiLCJjb250ZW50VHlwZVRhZ3MiOltdLCJjb3VudHJ5IjoiY2Fhczpjb3VudHJ5L3VzIiwiY3VzdG9tQ2FyZCI6IiIsImN0YUFjdGlvbiI6Il9zZWxmIiwiZG9Ob3RMYXp5TG9hZCI6ZmFsc2UsImRpc2FibGVCYW5uZXJzIjpmYWxzZSwiZHJhZnREYiI6ZmFsc2UsImVuZHBvaW50Ijoid3d3LmFkb2JlLmNvbS9jaGltZXJhLWFwaS9jb2xsZWN0aW9uIiwiZW52aXJvbm1lbnQiOiIiLCJleGNsdWRlZENhcmRzIjpbXSwiZXhjbHVkZVRhZ3MiOltdLCJmYWxsYmFja0VuZHBvaW50IjoiIiwiZmVhdHVyZWRDYXJkcyI6W10sImZpbHRlckV2ZW50IjoiIiwiZmlsdGVyQnVpbGRQYW5lbCI6ImF1dG9tYXRpYyIsImZpbHRlckxvY2F0aW9uIjoibGVmdCIsImZpbHRlckxvZ2ljIjoib3IiLCJmaWx0ZXJzIjpbXSwiZmlsdGVyc0N1c3RvbSI6W10sImZpbHRlcnNTaG93RW1wdHkiOmZhbHNlLCJndXR0ZXIiOiI0eCIsImhlYWRlcnMiOltdLCJoaWRlQ3RhSWRzIjpbXSwiaGlkZUN0YVRhZ3MiOltdLCJpbmNsdWRlVGFncyI6W10sImxhbmd1YWdlIjoiY2FhczpsYW5ndWFnZS9lbiIsImxheW91dFR5cGUiOiI0dXAiLCJsb2FkTW9yZUJ0blN0eWxlIjoicHJpbWFyeSIsIm5vdExvZ2ljVGFncyI6W10sIm9ubHlTaG93Qm9va21hcmtlZENhcmRzIjpmYWxzZSwib3JMb2dpY1RhZ3MiOltdLCJwYWdpbmF0aW9uQW5pbWF0aW9uU3R5bGUiOiJwYWdlZCIsInBhZ2luYXRpb25FbmFibGVkIjpmYWxzZSwicGFnaW5hdGlvblF1YW50aXR5U2hvd24iOmZhbHNlLCJwYWdpbmF0aW9uVHlwZSI6InBhZ2luYXRvciIsInBhZ2luYXRpb25Vc2VUaGVtZTMiOmZhbHNlLCJwbGFjZWhvbGRlclVybCI6IiIsInJlc3VsdHNQZXJQYWdlIjo1LCJzZWFyY2hGaWVsZHMiOltdLCJzZXRDYXJkQm9yZGVycyI6ZmFsc2UsInNob3dCb29rbWFya3NGaWx0ZXIiOmZhbHNlLCJzaG93Qm9va21hcmtzT25DYXJkcyI6ZmFsc2UsInNob3dGaWx0ZXJzIjpmYWxzZSwic2hvd1NlYXJjaCI6ZmFsc2UsInNob3dUb3RhbFJlc3VsdHMiOmZhbHNlLCJzb3J0RGF0ZUFzYyI6ZmFsc2UsInNvcnREYXRlRGVzYyI6ZmFsc2UsInNvcnREYXRlTW9kaWZpZWQiOmZhbHNlLCJzb3J0RGVmYXVsdCI6ImRhdGVEZXNjIiwic29ydEVuYWJsZVBvcHVwIjpmYWxzZSwic29ydEVuYWJsZVJhbmRvbVNhbXBsaW5nIjpmYWxzZSwic29ydEV2ZW50U29ydCI6ZmFsc2UsInNvcnRGZWF0dXJlZCI6ZmFsc2UsInNvcnRNb2RpZmllZEFzYyI6ZmFsc2UsInNvcnRNb2RpZmllZERlc2MiOmZhbHNlLCJzb3J0UmFuZG9tIjpmYWxzZSwic29ydFJlc2Vydm9pclBvb2wiOjEwMDAsInNvcnRSZXNlcnZvaXJTYW1wbGUiOjMsInNvcnRUaXRsZUFzYyI6ZmFsc2UsInNvcnRUaXRsZURlc2MiOmZhbHNlLCJzb3VyY2UiOlsiaGF3a3MiXSwidGFnc1VybCI6Ind3dy5hZG9iZS5jb20vY2hpbWVyYS1hcGkvdGFncyIsInRhcmdldEFjdGl2aXR5IjoiIiwidGFyZ2V0RW5hYmxlZCI6ZmFsc2UsInRoZW1lIjoibGlnaHRlc3QiLCJkZXRhaWxzVGV4dE9wdGlvbiI6ImRlZmF1bHQiLCJ0aXRsZUhlYWRpbmdMZXZlbCI6ImgzIiwidG90YWxDYXJkc1RvU2hvdyI6MTAsInVzZUxpZ2h0VGV4dCI6ZmFsc2UsInVzZU92ZXJsYXlMaW5rcyI6ZmFsc2UsImNvbGxlY3Rpb25CdXR0b25TdHlsZSI6InByaW1hcnkiLCJ1c2VySW5mbyI6W119')

// Windows/Linux encodes the hash very slightly differently than OSX
// This is due to different header values in the zip output
// Note the start of each hash:
// Win: ~~H4sIAAAAAAAAA3
// Osx: ~~H4sIAAAAAAAAE3

// This does not affect the decoded hash value,
// so either of these are valid hashes for the same content

const windowsHash = '~~H4sIAAAAAAAAA3VVTXPbNhD9Lzw7sVK3PehmyfbEM3KsRvL0kOl0VsBSxAjEsgAomen0v3cXpPihKDfiLfbr7cPy3wy0NtGQA/sV/6kxxDV4KEM2//bXTQYMN9GosCRrUcm9L1BiNs+ykXHrQR2ey8pjCHwjm+dgA8oFvaK9UVvYn+PVkZZUu+ibFbh9f3NHdCjBH54VuQ1KpjbFGH9zYWRR4PUmNlZqKcDmHwo0+yJ2lq2JFu+VkoJ2xprYrPCINpv/zva+lUV05xCVN5ynycbmodMBS4EvwY353mMugnHo+fjpl9nsBd7/NDoWnQld3DYVDnyolgu+rQDCvDve1kEc6hCpXHI3XewI9ykdH/9mKnLGNH2huILvzYpA92xqE2BncQGOKwkD7CGPD7v+jE5XZJwQejqdPoKmHX5UVN6qwpTo4QNU5nboMhOPo/HkSnTdFPBd2Vqjliq7ljpo6JGz2R0L5HFIx545Qqz9xDM3NqJ/PPbRW2BRG6vX4GR8SUAlsOh684oUdKxYzOMIZ+UxSL6HJnnCMvE7gTYFnR7LKjY9R/s6xjTNX985TIGg+zCF0biM8Kyn56Fx4y6YsCz5GvZ4Hvf5fItCroWG6qQPSVdXAvFUX8jjVaE6nvz0dZGzjbSw6F5Nz27XDPkLhwr2xiX27p0p00efh+vS2fjKoxNRDSobLH/U4CK/Mcntrti7njogDWQwvgXcFlji3eBoQWFBlql+87aVAq+W2sawRr9OBP52kwUEr4ong/Y8gYBRGl6Q12PdhxEl4SlN+rrt1U35EuPTWTkjbJMyT6AtRVmgqcjBQD4+QMT7oH7AHvAK+ELa5GbEcTJgDhyWedBnv9bQDmRNFWtl7NDiX3n7UrmBsrJmtGnTBXliG/6YoE/di5yA54ouWzjjP7TRpp1CGNAfyfg1EY/z02w2uzCkKnmqdy3ebu+LwAm8SFd7xV7f+AdwOoSMFRBZ2q1mfr7R5E4mV/0eo2zUo5EHn/XYpdCjyFPWi/xg+Acpexd5zduwxff4WnXbR3dzYgcp9TPvCia+++9kxZ0YRCVJY1uSxyJk3GR1wJWElmh9UgZfj+h5KayMOwyaGv29eDXRlb3Anv7Z5SRv4r//Ac4t/CbgBwAA';
const osxHash = '~~H4sIAAAAAAAAE3VVTXPbNhD9Lzw7sVK3PehmyfbEM3KsRvL0kOl0VsBSxAjEsgAomen0v3cXpPihKDfiLfbr7cPy3wy0NtGQA/sV/6kxxDV4KEM2//bXTQYMN9GosCRrUcm9L1BiNs+ykXHrQR2ey8pjCHwjm+dgA8oFvaK9UVvYn+PVkZZUu+ibFbh9f3NHdCjBH54VuQ1KpjbFGH9zYWRR4PUmNlZqKcDmHwo0+yJ2lq2JFu+VkoJ2xprYrPCINpv/zva+lUV05xCVN5ynycbmodMBS4EvwY353mMugnHo+fjpl9nsBd7/NDoWnQld3DYVDnyolgu+rQDCvDve1kEc6hCpXHI3XewI9ykdH/9mKnLGNH2huILvzYpA92xqE2BncQGOKwkD7CGPD7v+jE5XZJwQejqdPoKmHX5UVN6qwpTo4QNU5nboMhOPo/HkSnTdFPBd2Vqjliq7ljpo6JGz2R0L5HFIx545Qqz9xDM3NqJ/PPbRW2BRG6vX4GR8SUAlsOh684oUdKxYzOMIZ+UxSL6HJnnCMvE7gTYFnR7LKjY9R/s6xjTNX985TIGg+zCF0biM8Kyn56Fx4y6YsCz5GvZ4Hvf5fItCroWG6qQPSVdXAvFUX8jjVaE6nvz0dZGzjbSw6F5Nz27XDPkLhwr2xiX27p0p00efh+vS2fjKoxNRDSobLH/U4CK/Mcntrti7njogDWQwvgXcFlji3eBoQWFBlql+87aVAq+W2sawRr9OBP52kwUEr4ong/Y8gYBRGl6Q12PdhxEl4SlN+rrt1U35EuPTWTkjbJMyT6AtRVmgqcjBQD4+QMT7oH7AHvAK+ELa5GbEcTJgDhyWedBnv9bQDmRNFWtl7NDiX3n7UrmBsrJmtGnTBXliG/6YoE/di5yA54ouWzjjP7TRpp1CGNAfyfg1EY/z02w2uzCkKnmqdy3ebu+LwAm8SFd7xV7f+AdwOoSMFRBZ2q1mfr7R5E4mV/0eo2zUo5EHn/XYpdCjyFPWi/xg+Acpexd5zduwxff4WnXbR3dzYgcp9TPvCia+++9kxZ0YRCVJY1uSxyJk3GR1wJWElmh9UgZfj+h5KayMOwyaGv29eDXRlb3Anv7Z5SRv4r//Ac4t/CbgBwAA';
let isCorrectHash = false;
const hash = copyTextArea.value.split('#')[1];
if (hash === windowsHash || hash === osxHash) {
isCorrectHash = true;
}
expect(isCorrectHash).to.be.true;
});

it('Clones an object', () => {
Expand All @@ -305,13 +328,21 @@
expect(updateObj({ a: 'blah', d: 1234 }, allKeys)).to.eql({ a: 'blah', b: 2, c: [6, 7, 8], d: 1234 });
});

it('Converts Base 64 to UTF-8', () => {
it('Converts Verson1 Hash Base 64 to UTF-8', async () => {
const hash = 'eyJhZGRpdGlvbmFsUmVxdWVzdFBhcmFtcyI6W10sImFuYWx5dGljc0NvbGxlY3Rpb25OYW1lIjoiIiwiYW5hbHl0aWNzVHJhY2tJbXByZXNzaW9uIjpmYWxzZSwiYW5kTG9naWNUYWdzIjpbXSwiYXV0b0NvdW50cnlMYW5nIjpmYWxzZSwiYm9va21hcmtJY29uU2VsZWN0IjoiIiwiYm9va21hcmtJY29uVW5zZWxlY3QiOiIiLCJjYXJkU3R5bGUiOiJoYWxmLWhlaWdodCIsImNhcmRUaXRsZUFjY2Vzc2liaWxpdHlMZXZlbCI6NiwiY29sbGVjdGlvbkJ0blN0eWxlIjoicHJpbWFyeSIsImNvbGxlY3Rpb25OYW1lIjoiIiwiY29sbGVjdGlvblRpdGxlIjoiIiwiY29sbGVjdGlvblNpemUiOiIiLCJjb250YWluZXIiOiIxMjAwTWF4V2lkdGgiLCJjb250ZW50VHlwZVRhZ3MiOltdLCJjb3VudHJ5IjoiY2Fhczpjb3VudHJ5L3VzIiwiY3VzdG9tQ2FyZCI6IiIsImN0YUFjdGlvbiI6Il9ibGFuayIsImRvTm90TGF6eUxvYWQiOmZhbHNlLCJkaXNhYmxlQmFubmVycyI6ZmFsc2UsImRyYWZ0RGIiOmZhbHNlLCJlbmRwb2ludCI6Ind3dy5hZG9iZS5jb20vY2hpbWVyYS1hcGkvY29sbGVjdGlvbiIsImVudmlyb25tZW50IjoiIiwiZXhjbHVkZWRDYXJkcyI6W10sImV4Y2x1ZGVUYWdzIjpbXSwiZmFsbGJhY2tFbmRwb2ludCI6IiIsImZlYXR1cmVkQ2FyZHMiOltdLCJmaWx0ZXJFdmVudCI6IiIsImZpbHRlckJ1aWxkUGFuZWwiOiJhdXRvbWF0aWMiLCJmaWx0ZXJMb2NhdGlvbiI6ImxlZnQiLCJmaWx0ZXJMb2dpYyI6Im9yIiwiZmlsdGVycyI6W10sImZpbHRlcnNDdXN0b20iOltdLCJmaWx0ZXJzU2hvd0VtcHR5IjpmYWxzZSwiZ3V0dGVyIjoiNHgiLCJoZWFkZXJzIjpbXSwiaGVhZGVycyI6W10sImhpZGVDdGFJZHMiOltdLCJpbmNsdWRlVGFncyI6W10sImxhbmd1YWdlIjoiY2FhczpsYW5ndWFnZS9lbiIsImxheW91dFR5cGUiOiI0dXAiLCJsb2FkTW9yZUJ0blN0eWxlIjoicHJpbWFyeSIsIm9ubHlTaG93Qm9va21hcmtlZENhcmRzIjpmYWxzZSwib3JMb2dpY1RhZ3MiOltdLCJwYWdpbmF0aW9uQW5pbWF0aW9uU3R5bGUiOiJwYWdlZCIsInBhZ2luYXRpb25FbmFibGVkIjpmYWxzZSwicGFnaW5hdGlvblF1YW50aXR5U2hvd24iOmZhbHNlLCJwYWdpbmF0aW9uVHlwZSI6InBhZ2luYXRvciIsInBhZ2luYXRpb25Vc2VUaGVtZTMiOmZhbHNlLCJwbGFjZWhvbGRlclVybCI6IiIsInJlc3VsdHNQZXJQYWdlIjo1LCJzZWFyY2hGaWVsZHMiOltdLCJzZXRDYXJkQm9yZGVycyI6ZmFsc2UsInNob3dCb29rbWFya3NGaWx0ZXIiOmZhbHNlLCJzaG93Qm9va21hcmtzT25DYXJkcyI6ZmFsc2UsInNob3dGaWx0ZXJzIjpmYWxzZSwic2hvd1NlYXJjaCI6ZmFsc2UsInNob3dUb3RhbFJlc3VsdHMiOmZhbHNlLCJzb3J0RGF0ZUFzYyI6ZmFsc2UsInNvcnREYXRlRGVzYyI6ZmFsc2UsInNvcnREYXRlTW9kaWZpZWQiOmZhbHNlLCJzb3J0RGVmYXVsdCI6ImRhdGVEZXNjIiwic29ydEVuYWJsZVBvcHVwIjpmYWxzZSwic29ydEVuYWJsZVJhbmRvbVNhbXBsaW5nIjpmYWxzZSwic29ydEV2ZW50U29ydCI6ZmFsc2UsInNvcnRGZWF0dXJlZCI6ZmFsc2UsInNvcnRNb2RpZmllZEFzYyI6ZmFsc2UsInNvcnRNb2RpZmllZERlc2MiOmZhbHNlLCJzb3J0UmFuZG9tIjpmYWxzZSwic29ydFJlc2Vydm9pclBvb2wiOjEwMDAsInNvcnRSZXNlcnZvaXJTYW1wbGUiOjMsInNvcnRUaXRsZUFzYyI6ZmFsc2UsInNvcnRUaXRsZURlc2MiOmZhbHNlLCJzb3VyY2UiOlsiaGF3a3MiXSwidGFnc1VybCI6Ind3dy5hZG9iZS5jb20vY2hpbWVyYS1hcGkvdGFncyIsInRhcmdldEFjdGl2aXR5IjoiIiwidGFyZ2V0RW5hYmxlZCI6ZmFsc2UsInRoZW1lIjoibGlnaHRlc3QiLCJkZXRhaWxzVGV4dE9wdGlvbiI6ImRlZmF1bHQiLCJ0aXRsZUhlYWRpbmdMZXZlbCI6ImgzIiwidG90YWxDYXJkc1RvU2hvdyI6MTAsInVzZUxpZ2h0VGV4dCI6ZmFsc2UsInVzZU92ZXJsYXlMaW5rcyI6ZmFsc2UsImNvbGxlY3Rpb25CdXR0b25TdHlsZSI6InByaW1hcnkiLCJ1c2VySW5mbyI6W119';
window.location.hash = hash;
const hashConfig = getHashConfig();
const hashConfig = await getHashConfig();
expect(hashConfig.cardStyle).to.equal('half-height');
});

it('Converts Verson2 Gzipped Hash Base 64 to UTF-8', async () => {
const hash = '~~H4sIAAAAAAAAE3VVTXPbNhD9Lzw7sVK3PehmyfbEM3KsRvL0kOl0VsBSxAjEsgAomen0v3cX/JSi3Ii32K+3D8t/M9DaREMO7Ff8p8YQ1+ChDNn82183GTDcRKPCkqxFJfe+QInZPMsmxq0HdXguK48h8I1snoMNKBf0ivZGbWHfx6sjLal20TcrcPvh5o7oUII/PCtyG5RMbYop/ubCxKLA601srNSS19Z+EKDDtyZavFdKytkZa2KzwiPabP4724dGFtH1ASpvOEuTTc1jnyOWAl+CG/N9wFwE49Dz8dMvs9kLvP9pdCw6E7q4bSoc2VAtE3xbAYR5d7ytgzjUIVK5lKba2BHuUzo+/s1E5Ixp+kJxBd+bFYEeuNQmwM7iAhxXEkbYQx4fdsMZna7IOKHzdDp9BE07/KiovFWFKdHDB6jM7dhlJh5H48mV6LoZ4LuytUYtVXYtddDYI2ezO5bH45iOPXOEWPszz9zYiP7xOERvgUVtrF6Dk/El+ZTAkhvMK1LQsWIxjxOcdccg+QE6yxOWid8zaFPQ6bGsYjNwtK9jTNP89Z3DFAh6CFMYjcsIz/r8PDZu3AUTlgVfwx77cffnWxRyLTRUJ31IuroSiKf6Qh6vCpWcbaTgRfdCBi670slfPL0K9sYlru6dKdPHEJWrkLczXnl0IqFRU6Pljxpc5Bclud0Ve9dBByT6R+NbwG2BJd6NjhYUFmSZ2Ddv28HzGqltDGv060TXbzdZQPCqeDJoe74DRml4QV5PVR4mlISnNNfrtld3zpcYn3qdTLBNynwGbSnKskxFjgby8QEi3gf1A/aAV8AX0iY3E46TAXPgsMyD7v1aQzuQNVWsjKlDi3/lTUvlBsrKmslWTRfkQW344wx96t7fGdhXdNlCj//QRpv2HMKA/kjGr4l4nJ9ms9mFIVXJU71r8XZXXwRO4EW62iv2+pYVcDqEjBUQWdqtZn6+v+ROJlf9HqPsz6OR550N2KXQo8hTlonZF5F/hrJlkZe6DVt8j69Vt2t0Nyd2kFI/82Zg4ru/TFbciUFUkjS2JXksQsZNVgdcSWiJNiRl8PWInlfAyrjDqKnJv4oXEV3ZAuzpn11O7Ztw/DeYPvr//gcuiyqz3gcAAA==';
window.location.hash = hash;
// v2 getHashConfig is async
const hashConfig = await getHashConfig();
expect(hashConfig.cardStyle).to.equal('full-card');
});

});
</script>
</html>
Loading

0 comments on commit 202c33f

Please sign in to comment.