webamp/js/serialization.test.ts
2018-10-05 21:31:05 -07:00

239 lines
6.1 KiB
TypeScript

import fs from "fs";
import path from "path";
import reducer from "./reducers";
import * as Selectors from "./selectors";
import * as Actions from "./actionCreators";
import { kebabCase } from "lodash";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { LOAD_SERIALIZED_STATE } from "./actionTypes";
import { SerializedStateV1 } from "./serializedStates/v1Types";
import { Dispatchable, AppState } from "./types";
function fixturePath(name: string) {
return path.join(
__dirname,
"__tests__/fixtures/serializedState/v1/",
`${kebabCase(name)}.json`
);
}
function writeFixture(name: string, state: SerializedStateV1) {
fs.writeFileSync(fixturePath(name), JSON.stringify(state, null, 4));
}
function readFixture(name: string): SerializedStateV1 {
return JSON.parse(fs.readFileSync(fixturePath(name), "utf8"));
}
interface SerializationTestParams<T> {
name: string;
action: Dispatchable;
selector(state: AppState): T;
expected: T;
}
function testSerialization<T>({
name,
action,
selector,
expected
}: SerializationTestParams<T>) {
test(name, () => {
const firstStore = getStore();
// Does not match the expected selection in the initial state
expect(selector(firstStore.getState())).not.toEqual(expected);
firstStore.dispatch(action);
// Ensure we actually changed something
expect(firstStore.getState()).not.toEqual(getStore().getState());
// Ensure the expectation is true before we serialize
expect(selector(firstStore.getState())).toEqual(expected);
const serializedState = Selectors.getSerlializedState(
firstStore.getState()
);
if (!fs.existsSync(fixturePath(name))) {
writeFixture(name, serializedState);
console.warn("Wrote new fixture: ", fixturePath(name));
}
const readSerializedState = readFixture(name);
// Ensure our serialization strategy hasn't changed since we last serialized
expect(readSerializedState).toEqual(serializedState);
// Try to apply this serialized state to the default state
const secondStore = getStore();
secondStore.dispatch({
type: LOAD_SERIALIZED_STATE,
serializedState: readSerializedState
});
// Ensure our restored state conforms to expectation
expect(selector(secondStore.getState())).toEqual(expected);
// TODO: Try to apply the serialized state to a complex non-initial state
});
}
const defaultSerializedState = Selectors.getSerlializedState(
getStore().getState()
);
function getStore() {
const extras = {};
const enhancer = applyMiddleware(thunk.withExtraArgument(extras));
return createStore(reducer, enhancer);
}
describe("can serialize", () => {
test("the initial state", () => {
const store = getStore();
const serializedState = Selectors.getSerlializedState(store.getState());
expect(serializedState).toMatchSnapshot();
const newStore = getStore();
newStore.dispatch({
type: LOAD_SERIALIZED_STATE,
serializedState
});
expect(store.getState()).toEqual(newStore.getState());
});
/* Media */
testSerialization({
name: "volume",
action: Actions.setVolume(50),
selector: Selectors.getVolume,
expected: 50
});
testSerialization({
name: "balance",
action: Actions.setBalance(40),
selector: Selectors.getBalance,
expected: 40
});
testSerialization({
name: "shuffle",
action: Actions.toggleShuffle(),
selector: Selectors.getShuffle,
expected: true
});
testSerialization({
name: "repeat",
action: Actions.toggleRepeat(),
selector: Selectors.getRepeat,
expected: true
});
/* Equalizer */
testSerialization({
name: "equalizer on",
action: Actions.toggleEq(),
selector: Selectors.getEqualizerEnabled,
expected: false
});
testSerialization({
name: "equalizer auto",
action: Actions.toggleEqAuto(),
selector: Selectors.getEqualizerAuto,
expected: true
});
testSerialization({
name: "equalizer band",
action: Actions.setEqBand(60, 100),
selector: state => Selectors.getSliders(state)[60],
expected: 100
});
testSerialization({
name: "equalizer preamp",
action: Actions.setPreamp(10),
selector: state => Selectors.getSliders(state).preamp,
expected: 10
});
/* Display */
testSerialization({
name: "double mode",
action: Actions.toggleDoubleSizeMode(),
selector: Selectors.getDoubled,
expected: true
});
testSerialization({
name: "llama mode",
action: Actions.toggleLlamaMode(),
selector: Selectors.getLlamaMode,
expected: true
});
// TODO
// * marqueeStep
// * skinImages
// * skinCursors
// * skinRegion
// * skinGenLetterWidths
// * skinColors
// * skinPlaylistStyle
// * focused
/* Gen Windows */
testSerialization({
name: "window size",
action: Actions.setWindowSize("playlist", [4, 5]),
selector: state => Selectors.getWindowSize(state)("playlist"),
expected: [4, 5]
});
testSerialization({
name: "window open",
action: Actions.closeWindow("playlist"),
selector: state => Selectors.getWindowOpen(state)("playlist"),
expected: false
});
testSerialization({
name: "window hidden",
action: Actions.hideWindow("playlist"),
selector: state => Selectors.getWindowHidden(state)("playlist"),
expected: true
});
testSerialization({
name: "window shade",
action: Actions.toggleEqualizerShadeMode(),
selector: state => Selectors.getWindowShade(state)("equalizer"),
expected: true
});
testSerialization({
name: "main window position",
action: Actions.updateWindowPositions({ main: { x: 100, y: 100 } }),
selector: state => Selectors.getWindowPosition(state)("main"),
expected: { x: 100, y: 100 }
});
testSerialization({
name: "window positions are relative",
action: Actions.updateWindowPositions({ main: { x: 100, y: 100 } }, true),
selector: Selectors.getPositionsAreRelative,
expected: false
});
testSerialization({
name: "focused window",
action: Actions.setFocusedWindow("equalizer"),
selector: state => Selectors.getFocusedWindow(state),
expected: "equalizer"
});
});