mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-10 10:17:11 +03:00
c8a398e6e9
There's a bug when multiple gutters are prepended at once where their order is not correctly preserved in the dom. The issue is that we do not update indexInOldGutters even though we inserted a dom node in the old gutters dom. Honestly, I'm unconvinced that this entire logic is correct, but this fixes the use case we have in Nuclide so it's more correct than before :) Released under CC0
161 lines
8.8 KiB
CoffeeScript
161 lines
8.8 KiB
CoffeeScript
Gutter = require '../src/gutter'
|
|
GutterContainerComponent = require '../src/gutter-container-component'
|
|
DOMElementPool = require '../src/dom-element-pool'
|
|
|
|
describe "GutterContainerComponent", ->
|
|
[gutterContainerComponent] = []
|
|
mockGutterContainer = {}
|
|
|
|
buildTestState = (gutters) ->
|
|
styles =
|
|
scrollHeight: 100
|
|
scrollTop: 10
|
|
backgroundColor: 'black'
|
|
|
|
mockTestState = {gutters: []}
|
|
for gutter in gutters
|
|
if gutter.name is 'line-number'
|
|
content = {maxLineNumberDigits: 10, lineNumbers: {}}
|
|
else
|
|
content = {}
|
|
mockTestState.gutters.push({gutter, styles, content, visible: gutter.visible})
|
|
|
|
mockTestState
|
|
|
|
beforeEach ->
|
|
domElementPool = new DOMElementPool
|
|
mockEditor = {}
|
|
mockMouseDown = ->
|
|
gutterContainerComponent = new GutterContainerComponent({editor: mockEditor, onMouseDown: mockMouseDown, domElementPool, views: atom.views})
|
|
|
|
it "creates a DOM node with no child gutter nodes when it is initialized", ->
|
|
expect(gutterContainerComponent.getDomNode() instanceof HTMLElement).toBe true
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 0
|
|
|
|
describe "when updated with state that contains a new line-number gutter", ->
|
|
it "adds a LineNumberGutterComponent to its children", ->
|
|
lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'})
|
|
testState = buildTestState([lineNumberGutter])
|
|
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 0
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 1
|
|
expectedGutterNode = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedGutterNode.classList.contains('gutter')).toBe true
|
|
expectedLineNumbersNode = expectedGutterNode.children.item(0)
|
|
expect(expectedLineNumbersNode.classList.contains('line-numbers')).toBe true
|
|
|
|
expect(gutterContainerComponent.getLineNumberGutterComponent().getDomNode()).toBe expectedGutterNode
|
|
|
|
describe "when updated with state that contains a new custom gutter", ->
|
|
it "adds a CustomGutterComponent to its children", ->
|
|
customGutter = new Gutter(mockGutterContainer, {name: 'custom'})
|
|
testState = buildTestState([customGutter])
|
|
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 0
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 1
|
|
expectedGutterNode = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedGutterNode.classList.contains('gutter')).toBe true
|
|
expectedCustomDecorationsNode = expectedGutterNode.children.item(0)
|
|
expect(expectedCustomDecorationsNode.classList.contains('custom-decorations')).toBe true
|
|
|
|
describe "when updated with state that contains a new gutter that is not visible", ->
|
|
it "creates the gutter view but hides it, and unhides it when it is later updated to be visible", ->
|
|
customGutter = new Gutter(mockGutterContainer, {name: 'custom', visible: false})
|
|
testState = buildTestState([customGutter])
|
|
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 1
|
|
expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedCustomGutterNode.style.display).toBe 'none'
|
|
|
|
customGutter.show()
|
|
testState = buildTestState([customGutter])
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 1
|
|
expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedCustomGutterNode.style.display).toBe ''
|
|
|
|
describe "when updated with a gutter that already exists", ->
|
|
it "reuses the existing gutter view, instead of recreating it", ->
|
|
customGutter = new Gutter(mockGutterContainer, {name: 'custom'})
|
|
testState = buildTestState([customGutter])
|
|
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 1
|
|
expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0)
|
|
|
|
testState = buildTestState([customGutter])
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 1
|
|
expect(gutterContainerComponent.getDomNode().children.item(0)).toBe expectedCustomGutterNode
|
|
|
|
it "removes a gutter from the DOM if it does not appear in the latest state update", ->
|
|
lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'})
|
|
testState = buildTestState([lineNumberGutter])
|
|
gutterContainerComponent.updateSync(testState)
|
|
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 1
|
|
testState = buildTestState([])
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 0
|
|
|
|
describe "when updated with multiple gutters", ->
|
|
it "positions (and repositions) the gutters to match the order they appear in each state update", ->
|
|
lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'})
|
|
customGutter1 = new Gutter(mockGutterContainer, {name: 'custom', priority: -100})
|
|
testState = buildTestState([customGutter1, lineNumberGutter])
|
|
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 2
|
|
expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedCustomGutterNode).toBe atom.views.getView(customGutter1)
|
|
expectedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(1)
|
|
expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter)
|
|
|
|
# Add a gutter.
|
|
customGutter2 = new Gutter(mockGutterContainer, {name: 'custom2', priority: -10})
|
|
testState = buildTestState([customGutter1, customGutter2, lineNumberGutter])
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 3
|
|
expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1)
|
|
expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(1)
|
|
expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2)
|
|
expectedLineNumbersNode = gutterContainerComponent.getDomNode().children.item(2)
|
|
expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter)
|
|
|
|
# Hide one gutter, reposition one gutter, remove one gutter; and add a new gutter.
|
|
customGutter2.hide()
|
|
customGutter3 = new Gutter(mockGutterContainer, {name: 'custom3', priority: 100})
|
|
testState = buildTestState([customGutter2, customGutter1, customGutter3])
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 3
|
|
expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2)
|
|
expect(expectedCustomGutterNode2.style.display).toBe 'none'
|
|
expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(1)
|
|
expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1)
|
|
expectedCustomGutterNode3 = gutterContainerComponent.getDomNode().children.item(2)
|
|
expect(expectedCustomGutterNode3).toBe atom.views.getView(customGutter3)
|
|
|
|
it "reorders correctly when prepending multiple gutters at once", ->
|
|
lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'})
|
|
testState = buildTestState([lineNumberGutter])
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 1
|
|
expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedCustomGutterNode).toBe atom.views.getView(lineNumberGutter)
|
|
|
|
# Prepend two gutters at once
|
|
customGutter1 = new Gutter(mockGutterContainer, {name: 'first', priority: -200})
|
|
customGutter2 = new Gutter(mockGutterContainer, {name: 'second', priority: -100})
|
|
testState = buildTestState([customGutter1, customGutter2, lineNumberGutter])
|
|
gutterContainerComponent.updateSync(testState)
|
|
expect(gutterContainerComponent.getDomNode().children.length).toBe 3
|
|
expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0)
|
|
expect(expectedCustomGutterNode1).toBe atom.views.getView(customGutter1)
|
|
expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(1)
|
|
expect(expectedCustomGutterNode2).toBe atom.views.getView(customGutter2)
|