jsdom — отличный инструмент для textContent
— очень неудобный способ получить читаемый текст для преобразования html2text.
Есть замечательная статья о полезности ничтожных innerText
во многих случаях:
http://perfectionkills.com/the-poor-misunderstood-innerText/
Автор предлагает getSelection().toString()
как очень медленный обходной путь, но getSelection
еще не реализован в jsdom .
Не могли бы вы рассмотреть возможность реализации innerText
в jsdom ? Автор провел большое исследование этого, он даже добавил простую спецификацию в конце.
И как жаль , что стройный Selection
и innerText
библиотека не совместима с jsdom: https://github.com/timdown/rangy/issues/348
Итак, innerText не является стандартным и не реализован как минимум в одном крупном движке (Firefox). Без стандарта я не думаю, что мы должны его внедрять.
В Firefox реализовано: https://bugzilla.mozilla.org/show_bug.cgi?id=264412.
Семмы WHATWG для утверждения: https://github.com/whatwg/compat/issues/5#issuecomment -168049752
Из спецификации кажется, что мы не можем правильно реализовать innerText
без базовой поддержки макета.
Да, это все равно не будет реализовано в jsdom, без большой работы с инфраструктурой... никто не надеется :(.
Что касается требований к поддержке макета: https://github.com/rocallahan/innerText-spec/issues/2
Есть ли какие-либо планы по его внедрению в связи с принятием WHATWG?
Да ... Хотя спецификация требует много вещей, которых нет в jsdom, вокруг блоков CSS :(. Не знаю, что делать.
Есть ли какая-нибудь библиотека для этого, чтобы подключиться к jsdom?
@domenic не могли бы рассказать, почему это такая перестройка инфраструктуры? Мы думали, что 800-фунтовая горилла в комнате уйдет из дома. Но, похоже, никуда не денется. Как вы знаете, я ломал голову над внутренностями jsdom. С какого места в репозитории можно начать просмотр кода для новичка в jsdom?
Заранее спасибо 🙏 /cc @vsemozhetbyt
Основная проблема заключается в том, что innerText
руководствуется механизмом компоновки, а jsdom не имеет механизма компоновки. См. https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute и
http://perfectionkills.com/the-poor-misunderstood-innerText/ . Из второй ссылки:
Обратите внимание, как innerText почти точно представляет, как текст отображается на странице. textContent, с другой стороны, делает что-то странное — он игнорирует новые строки, созданные
и вокруг блочных элементов ( в данном случае).
Все еще выходит за рамки и нет обходного пути?
Видимо в спецификации написано:
Если этот элемент не визуализируется или если пользовательский агент не является пользовательским агентом CSS, [курсив мой] верните то же значение, что и IDL-атрибут textContent для этого элемента.
Я думаю, что тогда обходным путем было бы просто вернуть textContent
.
Мы реализуем столько CSS, что я не думаю, что это применимо. Мы просто не реализуем части макета...
Привет, ребята, есть новости по этому поводу?
Просто используйте безголовый хром :)
@domenic из той спецификации, которую упомянул
https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-атрибут
Если этот элемент не обрабатывается или если пользовательский агент не использует CSS, верните то же значение, что и IDL-атрибут
textContent
для этого элемента.
https://html.spec.whatwg.org/multipage/rendering.html#being -рендеринг
Элемент визуализируется, если он имеет какие-либо связанные блоки макета CSS, блоки макета SVG или некоторый эквивалент в других языках стилей.
Если jsdom
не реализует части макета, не означает ли это, что применяется «не отображается»?
Это сообщение предназначено для всех, кто обращается к этой ветке github и просто хочет, чтобы их тесты проходили без изменения реализации их функций.
копипаст для верхней части ваших тестовых файлов:
// Expose JSDOM Element constructor
global.Element = (new JSDOM()).window.Element;
// 'Implement' innerText in JSDOM: https://github.com/jsdom/jsdom/issues/1245
Object.defineProperty(global.Element.prototype, 'innerText', {
get() {
return this.textContent;
},
});
Естественно, применяются оговорки из приведенного выше обсуждения.
В случае, если кто-то еще сталкивается с этой проблемой, я сделал еще один шаг и использовал пакет sanitize-html
, чтобы получить в основном то, что делает браузер (обратите внимание, что я не импортировал настройку JSDOM, поскольку обнаружил, что она не нужна когда помещаю это в мой установочный файл Jest, но если вы не используете Jest, вам нужно использовать настройку global.Element = (new JSDOM()).window.Element
, рекомендованную @bennypowers ):
Object.defineProperty(global.Element.prototype, 'innerText', {
get() {
return sanitizeHtml(this.textContent, {
allowedTags: [], // remove all tags and return text content only
allowedAttributes: {}, // remove all tags and return text content only
});
},
configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
});
у меня была аналогичная потребность, но я хотел пойти немного дальше, чем просто использовать textContent
- опять же, это не будет точным представлением того, что на самом деле делают браузеры, особенно в отношении элементов, скрытых css, но это хорошо достаточно для моего варианта использования:
function innerText(el)
el = el.cloneNode(true) // can skip if mutability isn't a concern
el.querySelectorAll('script,style').forEach(s => s.remove())
return el.textContent
}
Какая жалость!
Видимо в спецификации написано:
Если этот элемент не визуализируется или если пользовательский агент не является пользовательским агентом CSS , [выделение добавлено], верните то же значение, что и IDL-атрибут textContent для этого элемента.
Я думаю, что обходным путем было бы просто вернуть textContent.
Мы реализуем столько CSS, что я не думаю, что это применимо. Мы просто не реализуем части макета...
@domenic, пожалуйста, рассмотрите более либеральную интерпретацию спецификации
textContent
явно разрешено в качестве запасного варианта, когда применение правил CSS слишком дорого.
также, innerText указан как геттер и сеттер
Учитывая, что я редактор спецификации, я могу с уверенностью заявить, что «когда применение правил CSS слишком дорого» — это не то, о чем говорится в спецификации.
.. это была моя интерпретация «если пользовательский агент не является пользовательским агентом CSS»
в чем разница между «пользовательским агентом CSS» и «пользовательским агентом без CSS»?
как насчет:
пользовательский агент CSS может «применять правила CSS» и выводить результат (графический или текстовый)
пользовательский агент, не использующий CSS, слишком глуп, чтобы «применять правила CSS»
Мы реализуем столько CSS, что я не думаю, что это применимо.
что ты имеешь в виду? окно.getComputedStyle?
откат к textContent все же лучше, чем отсутствие стандартного интерфейса
Возможно, мы можем просто использовать значение textContent
для замены результата innerText
при выполнении тестов с помощью jsdom
. Например:
describe('mytest', () => {
beforeAll(() => {
Object.defineProperty(HTMLElement.prototype, 'innerText', {
get() {
return this.textContent;
}
});
});
it('should ok', () => {
// test assertions
});
});
Самый полезный комментарий
В случае, если кто-то еще сталкивается с этой проблемой, я сделал еще один шаг и использовал пакет
sanitize-html
, чтобы получить в основном то, что делает браузер (обратите внимание, что я не импортировал настройку JSDOM, поскольку обнаружил, что она не нужна когда помещаю это в мой установочный файл Jest, но если вы не используете Jest, вам нужно использовать настройкуglobal.Element = (new JSDOM()).window.Element
, рекомендованную @bennypowers ):