Files
wekan/tests/htmljsArrayContent.test.cjs
T
Lauri Ojansivu e6ced014c5 Tests: make three .cjs suites runnable in a from-scratch node sandbox.
ldapConnectionRelease: strip comments before the source-guard search so a comment mentioning ldap.connect() (before the guarded call) no longer trips the 'connect inside the guard' assertion. htmljsArrayContent: provide a minimal Package global before requiring the vendored htmljs.js, which reads Package.meteor/Package.tracker at load before creating Package itself. ferretdbOplog: accept the hardcoded polling launcher form as well as the ${VAR:-polling} form. Source code unchanged; these are test-harness fixes surfaced by running the suite under a clean Node install.

Thanks to xet7.
2026-07-22 09:21:21 +03:00

93 lines
3.9 KiB
JavaScript

'use strict';
// Plain-Node unit test (no Meteor) for issue #6459: the card "More" menu
// rendered completely empty (no Delete option).
// Run: node tests/htmljsArrayContent.test.cjs
//
// Root cause: a WeKan-local vm-sandbox patch in the vendored jade compiler's
// htmljs made isConstructedObject(Array) return false (upstream htmljs returns
// true), so the HTML.Tag constructor took an ARRAY first argument — the
// compiled form of a tag with multi-part inline text like
// `label {{_ 'source-board'}}:` (a [TemplateTag, ":"] array) — as the tag's
// ATTRIBUTES dictionary instead of its content. At runtime Blaze then found a
// template view object inside the attributes and threw "The basic
// TransformingVisitor does not support foreign objects in attributes",
// killing the whole cardMorePopup render.
//
// The fix makes the Tag constructor treat an array first argument as content
// (like upstream), while keeping the vm-sandbox patch's answer for
// isConstructedObject(Array) itself (flattenAttributes depends on it).
const assert = require('assert');
// The vendored file is a sloppy-mode IIFE that publishes onto a `Package` global,
// but it FIRST reads Package.meteor.Meteor and Package.tracker.{Tracker,Deps} at the
// top — before its own `if (typeof Package === 'undefined') Package = {}` — so provide
// a minimal Package global here; the file then publishes Package.htmljs onto it.
global.Package = global.Package || {};
global.Package.meteor = global.Package.meteor || { Meteor: {} };
global.Package.tracker = global.Package.tracker || { Tracker: {}, Deps: {} };
require('../npm-packages/meteor-jade-loader/lib/vendor/htmljs.js');
const HTML = global.Package.htmljs.HTML;
let passed = 0;
function test(name, fn) {
fn();
passed += 1;
console.log(' ok -', name);
}
// --- POSITIVE: #6459 — an array first argument is tag CONTENT ---------------
test('array first argument becomes children, not attrs (the #6459 crash)', () => {
// Compiled shape of `label {{_ 'source-board'}}:` — inline text that is an
// array of [something-view-like, ':'].
const viewLike = { foo: 'templateTagPlaceholder' };
const tag = HTML.LABEL([viewLike, ':'], HTML.SELECT());
assert.strictEqual(tag.attrs, null, 'attrs must stay empty (prototype default)');
assert.strictEqual(tag.children.length, 2);
assert.ok(Array.isArray(tag.children[0]), 'first child is the inline-text array');
assert.strictEqual(tag.children[0][1], ':');
});
test('array-only tag keeps its content renderable', () => {
const tag = HTML.LABEL(['a', 'b']);
assert.strictEqual(tag.attrs, null);
assert.deepStrictEqual(tag.children[0], ['a', 'b']);
});
// --- NEGATIVE: everything that must keep working exactly as before ----------
test('plain object first argument is still the attributes dictionary', () => {
const tag = HTML.LABEL({ class: 'nice' }, 'text');
assert.deepStrictEqual(tag.attrs, { class: 'nice' });
assert.deepStrictEqual(tag.children, ['text']);
});
test('HTML.Attrs first argument is still unwrapped into attrs', () => {
const tag = HTML.LABEL(HTML.Attrs({ id: 'x' }), 'text');
assert.deepStrictEqual(tag.attrs, { id: 'x' });
assert.deepStrictEqual(tag.children, ['text']);
});
test('a constructed object (another tag) first argument is content', () => {
const inner = HTML.SPAN('y');
const tag = HTML.LABEL(inner, 'text');
assert.strictEqual(tag.attrs, null);
assert.strictEqual(tag.children[0], inner);
});
test('vm-sandbox patch stays: isConstructedObject(Array) is false', () => {
// flattenAttributes relies on arrays NOT being "constructed objects"; only
// the Tag constructor needed the array special-case.
assert.strictEqual(HTML.isConstructedObject([1, 2]), false);
});
test('no-argument tags still work', () => {
const tag = HTML.LABEL();
assert.strictEqual(tag.attrs, null);
assert.strictEqual(tag.children.length, 0);
});
console.log(`\n${passed} tests passed`);