1import * as assert from 'node:assert'; 2import { TAG_NAMES as $, NS, getTagID } from '../common/html.js'; 3import { type TagToken, TokenType } from '../common/token.js'; 4import { FormattingElementList, EntryType } from './formatting-element-list.js'; 5import { generateTestsForEachTreeAdapter } from 'parse5-test-utils/utils/common.js'; 6 7function createToken(name: $): TagToken { 8 return { 9 type: TokenType.START_TAG, 10 tagName: name, 11 tagID: getTagID(name), 12 ackSelfClosing: false, 13 selfClosing: false, 14 attrs: [], 15 location: null, 16 }; 17} 18 19generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => { 20 test('Insert marker', () => { 21 const list = new FormattingElementList(treeAdapter); 22 23 list.insertMarker(); 24 assert.strictEqual(list.entries.length, 1); 25 assert.strictEqual(list.entries[0].type, EntryType.Marker); 26 27 list.insertMarker(); 28 assert.strictEqual(list.entries.length, 2); 29 assert.strictEqual(list.entries[0].type, EntryType.Marker); 30 }); 31 32 test('Push element', () => { 33 const list = new FormattingElementList(treeAdapter); 34 const element1Token = createToken($.DIV); 35 const element2Token = createToken($.P); 36 const element1 = treeAdapter.createElement($.DIV, NS.HTML, []); 37 const element2 = treeAdapter.createElement($.P, NS.HTML, []); 38 39 list.pushElement(element1, element1Token); 40 assert.strictEqual(list.entries.length, 1); 41 assert.strictEqual(list.entries[0].type, EntryType.Element as const); 42 assert.strictEqual(list.entries[0].element, element1); 43 assert.strictEqual(list.entries[0].token, element1Token); 44 45 list.pushElement(element2, element2Token); 46 assert.strictEqual(list.entries.length, 2); 47 assert.strictEqual(list.entries[0].type, EntryType.Element); 48 assert.strictEqual(list.entries[0].element, element2); 49 assert.strictEqual(list.entries[0].token, element2Token); 50 }); 51 52 test('Insert element after bookmark', () => { 53 const list = new FormattingElementList(treeAdapter); 54 const element1 = treeAdapter.createElement($.DIV, NS.HTML, []); 55 const element2 = treeAdapter.createElement($.P, NS.HTML, []); 56 const element3 = treeAdapter.createElement($.SPAN, NS.HTML, []); 57 const element4 = treeAdapter.createElement($.TITLE, NS.HTML, []); 58 59 list.pushElement(element1, createToken($.DIV)); 60 list.bookmark = list.entries[0]; 61 62 list.pushElement(element2, createToken($.P)); 63 list.pushElement(element3, createToken($.SPAN)); 64 65 list.insertElementAfterBookmark(element4, createToken($.TITLE)); 66 67 assert.strictEqual(list.entries.length, 4); 68 expect(list.entries[2]).toHaveProperty('element', element4); 69 }); 70 71 test('Push element - Noah Ark condition', () => { 72 const list = new FormattingElementList(treeAdapter); 73 const token1 = createToken($.DIV); 74 const token2 = createToken($.DIV); 75 const token3 = createToken($.DIV); 76 const token4 = createToken($.DIV); 77 const token5 = createToken($.DIV); 78 const token6 = createToken($.DIV); 79 80 const element1 = treeAdapter.createElement($.DIV, NS.HTML, [ 81 { name: 'attr1', value: 'val1' }, 82 { name: 'attr2', value: 'val2' }, 83 ]); 84 85 const element2 = treeAdapter.createElement($.DIV, NS.HTML, [ 86 { name: 'attr1', value: 'val1' }, 87 { name: 'attr2', value: 'someOtherValue' }, 88 ]); 89 90 list.pushElement(element1, token1); 91 list.pushElement(element1, token2); 92 list.pushElement(element2, token3); 93 list.pushElement(element1, token4); 94 95 assert.strictEqual(list.entries.length, 4); 96 expect(list.entries[3]).toHaveProperty('token', token1); 97 expect(list.entries[2]).toHaveProperty('token', token2); 98 expect(list.entries[1]).toHaveProperty('token', token3); 99 expect(list.entries[0]).toHaveProperty('token', token4); 100 101 list.pushElement(element1, token5); 102 103 assert.strictEqual(list.entries.length, 4); 104 expect(list.entries[3]).toHaveProperty('token', token2); 105 expect(list.entries[2]).toHaveProperty('token', token3); 106 expect(list.entries[1]).toHaveProperty('token', token4); 107 expect(list.entries[0]).toHaveProperty('token', token5); 108 109 list.insertMarker(); 110 list.pushElement(element1, token6); 111 112 assert.strictEqual(list.entries.length, 6); 113 expect(list.entries[5]).toHaveProperty('token', token2); 114 expect(list.entries[4]).toHaveProperty('token', token3); 115 expect(list.entries[3]).toHaveProperty('token', token4); 116 expect(list.entries[2]).toHaveProperty('token', token5); 117 expect(list.entries[1]).toHaveProperty('type', EntryType.Marker); 118 expect(list.entries[0]).toHaveProperty('token', token6); 119 }); 120 121 test('Clear to the last marker', () => { 122 const list = new FormattingElementList(treeAdapter); 123 const token = createToken($.DIV); 124 125 const element1 = treeAdapter.createElement($.DIV, NS.HTML, [ 126 { name: 'attr1', value: 'val1' }, 127 { name: 'attr2', value: 'val2' }, 128 ]); 129 130 const element2 = treeAdapter.createElement($.DIV, NS.HTML, [ 131 { name: 'attr1', value: 'val1' }, 132 { name: 'attr2', value: 'someOtherValue' }, 133 ]); 134 135 list.pushElement(element1, token); 136 list.pushElement(element2, token); 137 list.insertMarker(); 138 list.pushElement(element1, token); 139 list.pushElement(element1, token); 140 list.pushElement(element2, token); 141 142 list.clearToLastMarker(); 143 144 assert.strictEqual(list.entries.length, 2); 145 146 list.clearToLastMarker(); 147 148 assert.strictEqual(list.entries.length, 0); 149 }); 150 151 test('Remove entry', () => { 152 const list = new FormattingElementList(treeAdapter); 153 const token = createToken($.DIV); 154 155 const element1 = treeAdapter.createElement($.DIV, NS.HTML, [ 156 { name: 'attr1', value: 'val1' }, 157 { name: 'attr2', value: 'val2' }, 158 ]); 159 160 const element2 = treeAdapter.createElement($.DIV, NS.HTML, [ 161 { name: 'attr1', value: 'val1' }, 162 { name: 'attr2', value: 'someOtherValue' }, 163 ]); 164 165 list.pushElement(element1, token); 166 list.pushElement(element2, token); 167 list.pushElement(element2, token); 168 169 list.removeEntry(list.entries[2]); 170 171 assert.strictEqual(list.entries.length, 2); 172 173 for (let i = 0; i < list.entries.length; i++) { 174 expect(list.entries[i]).not.toHaveProperty('element', element1); 175 } 176 }); 177 178 test('Get entry in scope with given tag name', () => { 179 const list = new FormattingElementList(treeAdapter); 180 const token = createToken($.DIV); 181 const element = treeAdapter.createElement($.DIV, NS.HTML, []); 182 183 assert.ok(!list.getElementEntryInScopeWithTagName($.DIV)); 184 185 list.pushElement(element, token); 186 list.pushElement(element, token); 187 assert.strictEqual(list.getElementEntryInScopeWithTagName($.DIV), list.entries[0]); 188 189 list.insertMarker(); 190 assert.ok(!list.getElementEntryInScopeWithTagName($.DIV)); 191 192 list.pushElement(element, token); 193 assert.strictEqual(list.getElementEntryInScopeWithTagName($.DIV), list.entries[0]); 194 }); 195 196 test('Get element entry', () => { 197 const list = new FormattingElementList(treeAdapter); 198 const token = createToken($.DIV); 199 const element1 = treeAdapter.createElement($.DIV, NS.HTML, []); 200 const element2 = treeAdapter.createElement($.A, NS.HTML, []); 201 202 list.pushElement(element2, token); 203 list.pushElement(element1, token); 204 list.pushElement(element2, token); 205 list.insertMarker(); 206 207 const entry = list.getElementEntry(element1); 208 209 assert.ok(entry); 210 assert.strictEqual(entry.type, EntryType.Element); 211 assert.strictEqual(entry.token, token); 212 assert.strictEqual(entry.element, element1); 213 }); 214}); 215