Ekapp/swagger/test/unit/plugins/editor/editor.js

595 lines
16 KiB
JavaScript

import expect, { createSpy } from "expect"
import rewiremock from "rewiremock"
import Enzyme, { shallow } from "enzyme"
import Adapter from "enzyme-adapter-react-15"
import React from "react"
import FakeAce, { Session } from "test/unit/mocks/ace.js"
import { fromJS } from "immutable"
const pause = (ms) => new Promise((res) => setTimeout(res, ms))
const EVENTUALLY = 900 // ms
/**
* We're mocking out the editor,
* so uses of the phrase "should see this in editor",
* will match to the following Ace methods:
*
* - "what user see's in editor" => fakeAce.userSees()
* - "user types something (end of document)" => fakeAce.userTypes("hi")
* - "Ctrl-Z" => fakeAce.userUndo()
* - "Ctrl-Shift-Z" => fakeAce.userRedo()
**/
describe("editor", function() {
before(function () {
// Enzyme.configure({ adapter: new Adapter()})
Enzyme.configure({ adapter: new Adapter()})
// Whole bunch of mocks!
rewiremock.enable()
rewiremock("brace/mode/yaml").with({})
rewiremock("brace/theme/tomorrow_night_eighties").with({})
rewiremock("brace/ext/language_tools").with({})
rewiremock("brace/ext/searchbox").with({})
rewiremock("./brace-snippets-yaml").with({})
rewiremock("./editor.less").with({})
})
after(function() {
rewiremock.disable()
})
beforeEach(function() {
delete require.cache[require.resolve("react-ace")]
})
describe("fake ace", function() {
it("should be an event emitter", () => {
// Given
const fakeAce = new FakeAce()
const spy = createSpy()
fakeAce.on("foo", spy)
// When
fakeAce.emit("foo", "bar")
// Then
expect(spy.calls.length).toEqual(1)
expect(spy.calls[0].arguments[0]).toEqual("bar")
})
it("should return `this`, when calling .edit", function() {
// Given
const fakeAce = new FakeAce()
// When
const res = fakeAce.edit()
// Then
expect(res).toBe(fakeAce)
})
it("should keep track of setValue", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.setValue("foo")
// Then
const res = fakeAce.getValue()
expect(res).toEqual("foo")
})
it("should spy on setValue", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.setValue("foo")
// Then
expect(fakeAce.setValue.calls.length).toEqual(1)
expect(fakeAce.setValue.calls[0].arguments[0]).toEqual("foo")
})
it("should return a single session, with getSession", function() {
// Given
const fakeAce = new FakeAce()
// When
const res = fakeAce.getSession()
// Then
expect(res).toBeA(Session)
})
it("should add options via setOptions", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.setOptions({one: "uno"})
// Then
const res = fakeAce.getOption("one")
expect(res).toEqual("uno")
})
describe("userUndo/Redo", function() {
it("should revert to last input", function() {
// Given
const fakeAce = new FakeAce()
fakeAce.userTypes("one")
// When
fakeAce.userTypes("two")
// Then
fakeAce.userUndo()
expect(fakeAce.userSees()).toEqual("one")
})
it("should revert to empty document, no changes were made", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.userUndo()
// Then
expect(fakeAce.userSees()).toEqual("")
})
it("should revert to empty document, after arbitrary undos", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.userUndo()
fakeAce.userUndo()
fakeAce.userUndo()
fakeAce.userUndo()
// Then
expect(fakeAce.userSees()).toEqual("")
})
it("should not extend redos after last change", function() {
// Given
const fakeAce = new FakeAce()
fakeAce.userTypes("x")
// When
fakeAce.userRedo()
fakeAce.userRedo()
fakeAce.userRedo()
// Then
expect(fakeAce.userSees()).toEqual("x")
})
it("should allow redo after single undo", function() {
// Given
const fakeAce = new FakeAce()
fakeAce.userTypes("x")
fakeAce.userTypes("x")
fakeAce.userUndo()
// When
fakeAce.userRedo()
// Then
expect(fakeAce.userSees()).toEqual("xx")
})
it("should create new thread of undo stack, after new change", function() {
// Given
const fakeAce = new FakeAce()
fakeAce.userTypes("1")
fakeAce.userTypes("2")
fakeAce.userTypes("3")
fakeAce.userTypes("4")
fakeAce.userUndo() // 123
fakeAce.userUndo() // 12
fakeAce.userTypes("5") // 125
// When
fakeAce.userRedo() // 125, don't extend beyond
// Then
expect(fakeAce.userSees()).toEqual("125")
})
})
describe("fake session", function() {
it("should keep add state for markers", function() {
// Given
const fakeAce = new FakeAce()
const fakeSession = fakeAce.getSession()
// When
fakeSession.addMarker({one: 1})
// Then
const res = fakeSession.getMarkers()
expect(res).toBeAn("array")
expect(res.length).toEqual(1)
expect(res[0]).toEqual({id: 0, one: 1})
})
it("should keep remove state for markers", function() {
// Given
const fakeAce = new FakeAce()
const fakeSession = fakeAce.getSession()
fakeSession.addMarker({one: 1})
// When
fakeSession.removeMarker(0)
// Then
const res = fakeSession.getMarkers()
expect(res).toBeAn("array")
expect(res.length).toEqual(0)
})
it("should spy on addMarker", function() {
// Given
const fakeAce = new FakeAce()
const fakeSession = fakeAce.getSession()
// When
fakeSession.addMarker({one: 1})
// Then
expect(fakeSession.addMarker.calls.length).toEqual(1)
})
it("should spy on setMode", function() {
// Given
const fakeAce = new FakeAce()
const fakeSession = fakeAce.getSession()
// When
fakeSession.setMode()
// Then
expect(fakeSession.setMode.calls.length).toEqual(1)
})
it("should have a .selection which includes toJSON, fromJSON", function() {
// Given
const fakeAce = new FakeAce()
// When
const fakeSession = fakeAce.getSession()
// Then
expect(fakeSession.selection).toIncludeKey("toJSON")
expect(fakeSession.selection).toIncludeKey("fromJSON")
})
describe("userTypes", function() {
it("should emit 'change'", function() {
// Given
const fakeAce = new FakeAce()
const spy = createSpy()
fakeAce.on("change", spy)
// When
fakeAce.userTypes("hello")
// Then
expect(spy.calls.length).toBeGreaterThan(1)
})
it("should change the value", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.userTypes("hello")
// Then
expect(fakeAce.getValue()).toEqual("hello")
})
})
describe("userSees", function() {
it("should match userTypes", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.userTypes("hi")
// Then
const res = fakeAce.userSees()
expect(res).toEqual("hi")
})
it("should match setValue", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.setValue("hello")
// Then
const res = fakeAce.userSees()
expect(res).toEqual("hello")
})
})
})
describe("renderer", function() {
it("should have a stub for setShowGutter", function() {
// Given
const fakeAce = new FakeAce()
// When
fakeAce.renderer.setShowGutter("foo")
// Then
expect(fakeAce.renderer.setShowGutter.calls.length).toEqual(1)
expect(fakeAce.renderer.setShowGutter.calls[0].arguments[0]).toEqual("foo")
})
})
})
describe("editor component", function() {
it("should EVENTUALLY call onChange when user enters input", (done) => {
// Given
const fakeAce = new FakeAce()
rewiremock("brace").with(fakeAce)
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
const spy = createSpy()
const wrapper = shallow(
<Editor onChange={spy} />
)
wrapper
.find("ReactAce").shallow()
// When
// Simulate user input
fakeAce.userTypes("hello")
// Then
setTimeout(() => {
expect(spy.calls.length).toEqual(1)
expect(spy.calls[0].arguments[0]).toEqual("hello")
done()
}, EVENTUALLY)
})
it("should EVENTUALLY put the contents of `value` prop into editor, without regard to `origin` property", (done) => {
// Given
const fakeAce = new FakeAce()
rewiremock("brace").with(fakeAce)
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
// When
const wrapper = shallow(
<Editor value={"original value"} />
)
wrapper.find("ReactAce").shallow()
// Then
setTimeout(() => {
expect(fakeAce.userSees()).toEqual("original value")
done()
}, EVENTUALLY)
})
it("should EVENTUALLY put the contents of `value` prop into editor, with `foo` origin property ", (done) => {
// Given
const fakeAce = new FakeAce()
rewiremock("brace").with(fakeAce)
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
// When
const wrapper = shallow(
<Editor value={"original value"} origin="foo" />
)
wrapper.find("ReactAce").shallow()
// Then
setTimeout(() => {
expect(fakeAce.userSees()).toEqual("original value")
done()
}, EVENTUALLY)
})
it("should NEVER update ace if the yaml originated in editor", async () => {
// Given
const fakeAce = new FakeAce()
rewiremock("brace").with(fakeAce)
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
// When
const wrapper = shallow(
<Editor value="original value" />
)
wrapper.find("ReactAce").shallow()
wrapper.setProps({value: "new value", origin: "editor"})
// Then
await pause(EVENTUALLY)
expect(fakeAce.userSees()).toEqual("original value")
})
// SKIPPED: Does this have any value at this level? And not editor-container?
it.skip("SKIP: should EVENTUALLY call onChange ONCE if the user types/pauses/types", async function() {
this.timeout(10000)
// Given
const fakeAce = new FakeAce()
rewiremock("brace").with(fakeAce)
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
const spy = createSpy()
const wrapper = shallow(
<Editor value="original value" onChange={spy}/>
)
wrapper.find("ReactAce").shallow()
// When
fakeAce.userTypes(" one")
await pause(EVENTUALLY / 2)
fakeAce.userTypes("two")
await pause(EVENTUALLY / 2)
fakeAce.userTypes("three")
await pause(EVENTUALLY / 2)
await pause(EVENTUALLY * 2)
expect(fakeAce.userSees()).toEqual("original value onetwothree")
expect(spy.calls.length).toEqual(1)
})
it("should EVENTUALLY call onChange when ctrl-z", async function() {
this.timeout(10000)
// Given
const fakeAce = new FakeAce()
rewiremock("brace").with(fakeAce)
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
const spy = createSpy()
const wrapper = shallow(
<Editor value="original value" onChange={spy}/>
)
wrapper.find("ReactAce").shallow()
fakeAce.userTypes("one")
// When
fakeAce.userUndo()
await pause(EVENTUALLY)
expect(fakeAce.userSees()).toEqual("original value")
expect(spy.calls.length).toEqual(1)
})
describe("markers", function() {
it("should place markers into editor", async function() {
// Given
const fakeAce = new FakeAce()
const spy = createSpy()
rewiremock("brace").with(fakeAce)
rewiremock("../editor-helpers/marker-placer").with({placeMarkerDecorations: spy})
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
const dummy = fromJS({one: 1})
const wrapper = shallow(
<Editor markers={dummy} />
)
// When
wrapper.find("ReactAce").shallow()
await pause(EVENTUALLY)
// Then
expect(spy.calls.length).toEqual(1)
expect(spy.calls[0].arguments[0]).toInclude({markers: {one: 1}})
})
it("should place markers after yaml", async function() {
// Given
const order = []
const fakeAce = new FakeAce()
fakeAce.setValue.andCall(() => order.push("setValue"))
const spy = createSpy().andCall(() => order.push("placeMarkers"))
rewiremock("brace").with(fakeAce)
rewiremock("../editor-helpers/marker-placer").with({placeMarkerDecorations: spy})
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
const wrapper = shallow(
<Editor value="original value" markers={{}} />
)
// When
wrapper.find("ReactAce").shallow()
await pause(EVENTUALLY)
// Then
expect(order).toEqual(["setValue", "placeMarkers"])
})
it.skip("should Test for markers being disabled/enabled during a yaml update", async function() {
// Given
const order = []
const fakeAce = new FakeAce()
fakeAce.setValue.andCall(() => order.push("setValue"))
const spy = createSpy().andCall(() => {
order.push("placeMarkers")
return () => order.push("removeMarkers")
})
rewiremock("brace").with(fakeAce)
rewiremock("../editor-helpers/marker-placer").with({placeMarkerDecorations: spy})
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
const wrapper = shallow(
<Editor value="original value" markers={{}} />
)
wrapper.find("ReactAce").shallow()
// When
wrapper.setProps({value: "new value", origin: "bob"})
await pause(EVENTUALLY)
// Then
expect(order).toEqual(["setValue", "placeMarkers", "removeMarkers", "setValue", "placeMarkers"])
})
it.skip("should Test for markers being disabled/enabled during ctrl-z", async function() {
// Given
const order = []
const fakeAce = new FakeAce()
fakeAce.setValue.andCall(() => order.push("setValue"))
const spy = createSpy().andCall(() => {
order.push("placeMarkers")
return () => order.push("removeMarkers")
})
rewiremock("brace").with(fakeAce)
rewiremock("../editor-helpers/marker-placer").with({placeMarkerDecorations: spy})
const makeEditor = require("plugins/editor/components/editor.jsx").default
const Editor = makeEditor({})
const wrapper = shallow(
<Editor value="original value" markers={{}} />
)
wrapper.find("ReactAce").shallow()
// When
fakeAce.userUndo()
await pause(EVENTUALLY)
// Then
expect(order).toEqual(["setValue", "placeMarkers", "removeMarkers", "setValue", "placeMarkers"])
})
})
})
})