chore: Update ha-nunjucks to 1.6.2 (#2549)

- Replaces:
https://github.com/dermotduffy/advanced-camera-card/pull/2515
This commit is contained in:
Dermot Duffy
2026-06-30 17:45:13 -07:00
committed by dermotduffy
parent 015fb1876d
commit c3d3dd3934
15 changed files with 113 additions and 14 deletions
+6
View File
@@ -20,6 +20,12 @@ The Advanced Camera Card uses
Consult its documentation for the wide variety of different template values
supported.
> [!NOTE]
> To keep the card lightweight, some template features are not available. If a
> template feature you need is missing,
> [open an issue](https://github.com/dermotduffy/advanced-camera-card/issues) to
> request it.
See [an example](../examples.md?id=accessing-home-assistant-state) that
accesses Home Assistant state.
+1 -1
View File
@@ -31,7 +31,7 @@
"date-fns": "^3.6.0",
"embla-carousel": "^8.6.0",
"embla-carousel-wheel-gestures": "^8.0.1",
"ha-nunjucks": "^1.3.0",
"ha-nunjucks": "~1.6.2",
"home-assistant-js-websocket": "^9.4.0",
"js-yaml": "^4.1.0",
"keycharm": "^0.4.0",
+10 -1
View File
@@ -35,7 +35,16 @@ const serveopts = {
* @type {import('rollup').RollupOptions['plugins']}
*/
const plugins = [
gitInfo.default({ enableBuildDate: true, updateVersion: false }),
gitInfo.default(
// Limit git-info to the project's own package.json. Without this it also
// rewrites any dependency's imported package.json into ESM, which then breaks
// the json() plugin downstream (ha-nunjucks imports its own package.json).
{
enableBuildDate: true,
updateVersion: false,
include: 'package.json',
},
),
styles({
modules: false,
// Behavior of inject mode, without actually injecting style
@@ -8,8 +8,15 @@ import type {
BrowseMediaMetadata,
RichBrowseMedia,
} from '../../../../src/ha/browse-media/types';
import { createHASS, createMockTemplateRenderer } from '../../../test-utils';
import {
createHASS,
createMockTemplateRenderer,
stubConnectedHomeAssistant,
} from '../../../test-utils';
// The `with template matcher` test loads the real ha-nunjucks engine, which
// reads `window`/`document` at import, so this suite needs a DOM environment.
// @vitest-environment jsdom
describe('MediaMatcher', () => {
// A mock renderer for the matcher plumbing, which never renders templates.
// The `value_template` suite below uses its own real, loaded engine.
@@ -153,6 +160,7 @@ describe('MediaMatcher', () => {
// renderer (rather than the shared mock).
const templateManager = new TemplateManager();
beforeAll(async () => {
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
});
+12 -2
View File
@@ -1,9 +1,19 @@
import { describe, expect, it, vi } from 'vitest';
import { beforeAll, describe, expect, it, vi } from 'vitest';
import { TemplateManager } from '../../../src/card-controller/templates/index';
import { createConfig, createHASS, createStateEntity } from '../../test-utils';
import {
createConfig,
createHASS,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../test-utils';
// ha-nunjucks reads `window`/`document` at import and renders via a
// `window.haNunjucks` global, so the renderer needs a DOM environment.
// @vitest-environment jsdom
describe('TemplateManager', () => {
beforeAll(() => stubConnectedHomeAssistant());
describe('loadRenderer', () => {
it('should render a template raw before the engine is loaded', () => {
const manager = new TemplateManager();
@@ -6,6 +6,7 @@ import {
createHASS,
createMockTemplateRenderer,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../test-utils';
// @vitest-environment jsdom
@@ -66,6 +67,7 @@ describe('renderTimePeriodToSeconds', () => {
const templateManager = new TemplateManager();
beforeAll(async () => {
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
});
@@ -7,6 +7,7 @@ import {
createHASS,
createMockTemplateRenderer,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../test-utils';
// A mock renderer for the orchestration tests, which never render templates.
@@ -198,6 +199,7 @@ describe('ConditionsManager', () => {
// loaded for the synchronous renderer (rather than the shared mock).
const templateManager = new TemplateManager();
beforeAll(async () => {
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
});
@@ -6,6 +6,7 @@ import {
createHASS,
createMockTemplateRenderer,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../../test-utils';
import { createEvaluatorContext } from './test-utils';
@@ -131,6 +132,7 @@ describe('numeric state condition', () => {
// This case renders a real value_template, so load the lazily-imported
// engine for the synchronous renderer.
const templateManager = new TemplateManager();
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
const evaluator = createConditionEvaluator(
@@ -2,7 +2,11 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { TemplateManager } from '../../../../src/card-controller/templates';
import { createConditionEvaluator } from '../../../../src/condition-trigger/conditions/factory';
import { createHASS, createStateEntity } from '../../../test-utils';
import {
createHASS,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../../test-utils';
import { createEvaluatorContext } from './test-utils';
// @vitest-environment jsdom
@@ -340,6 +344,7 @@ describe('state condition', () => {
// This case renders a real templated `for`, so load the lazily-imported
// engine for the synchronous renderer.
const templateManager = new TemplateManager();
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
const evaluator = createConditionEvaluator(
@@ -2,13 +2,18 @@ import { beforeAll, describe, expect, it } from 'vitest';
import { TemplateManager } from '../../../../src/card-controller/templates';
import { createConditionEvaluator } from '../../../../src/condition-trigger/conditions/factory';
import { createHASS, createStateEntity } from '../../../test-utils';
import {
createHASS,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../../test-utils';
import { createEvaluatorContext } from './test-utils';
// @vitest-environment jsdom
describe('template condition', () => {
const templateManager = new TemplateManager();
beforeAll(async () => {
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
});
@@ -9,6 +9,7 @@ import {
createHASSManager,
createMockTemplateRenderer,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../test-utils';
const templateManager = createMockTemplateRenderer();
@@ -126,6 +127,7 @@ describe('TriggersManager', () => {
// loaded for the synchronous renderer (rather than the shared mock).
const templateManager = new TemplateManager();
beforeAll(async () => {
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
});
@@ -8,7 +8,11 @@ import {
import { ConditionStateManager } from '../../../../src/condition-trigger/conditions/state-manager';
import { NumericStateTrigger } from '../../../../src/condition-trigger/triggers/triggers/numeric-state';
import type { TriggerOfType } from '../../../../src/condition-trigger/triggers/triggers/types';
import { createHASS, createStateEntity } from '../../../test-utils';
import {
createHASS,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../../test-utils';
import { createTriggerEvaluatorContext } from './test-utils';
const SENSOR = 'sensor.temperature';
@@ -163,6 +167,7 @@ describe('NumericStateTrigger', () => {
it('should match the rendered value_template', async () => {
const templateManager = new TemplateManager();
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
const { trigger, stateManager, callback } = create(
@@ -13,11 +13,16 @@ import { TemplateManager } from '../../../../src/card-controller/templates';
import { ConditionStateManager } from '../../../../src/condition-trigger/conditions/state-manager';
import { TemplateTrigger } from '../../../../src/condition-trigger/triggers/triggers/template';
import type { TriggerOfType } from '../../../../src/condition-trigger/triggers/triggers/types';
import { createHASS, createStateEntity } from '../../../test-utils';
import {
createHASS,
createStateEntity,
stubConnectedHomeAssistant,
} from '../../../test-utils';
import { createTriggerEvaluatorContext } from './test-utils';
const templateManager = new TemplateManager();
beforeAll(async () => {
stubConnectedHomeAssistant();
await templateManager.loadRenderer();
});
+30
View File
@@ -758,6 +758,36 @@ export const createMockTemplateRenderer = (): TemplateManager => {
return renderer;
};
// At import the real ha-nunjucks engine waits for a connected `home-assistant`
// element before finishing initialization, retrying on a timer that can outlive
// the test (and throw `document is not defined` once the environment is torn
// down). Test suites that load the real engine call this first, in a jsdom
// environment, so it initializes immediately as it does in a real Home
// Assistant frontend. Idempotent.
//
// Workaround for an upstream bug; remove once it is fixed:
// https://github.com/Nerwyn/ha-nunjucks/issues/11
export const stubConnectedHomeAssistant = (): void => {
if (document.querySelector('home-assistant')) {
return;
}
const ha = document.createElement('home-assistant');
Object.assign(ha, {
hass: {
// The readiness gate the engine polls for.
connected: true,
connection: {
connected: true,
// Awaited by the engine's label-registry fetch during init.
sendMessagePromise: () => Promise.resolve([]),
},
language: 'en',
states: {},
},
});
document.body.appendChild(ha);
};
export const createCardAPI = (): CardController => {
const api = mock<CardController>();
+13 -5
View File
@@ -2662,7 +2662,7 @@ __metadata:
eslint-config-airbnb-base: "npm:^15.0.0"
eslint-config-prettier: "npm:^9.1.0"
eslint-plugin-import: "npm:^2.29.1"
ha-nunjucks: "npm:^1.3.0"
ha-nunjucks: "npm:~1.6.2"
home-assistant-js-websocket: "npm:^9.4.0"
js-yaml: "npm:^4.1.0"
jsdom: "npm:^21.1.2"
@@ -5786,14 +5786,15 @@ __metadata:
languageName: node
linkType: hard
"ha-nunjucks@npm:^1.3.0":
version: 1.3.0
resolution: "ha-nunjucks@npm:1.3.0"
"ha-nunjucks@npm:~1.6.2":
version: 1.6.2
resolution: "ha-nunjucks@npm:1.6.2"
dependencies:
home-assistant-js-websocket: "npm:latest"
nunjucks: "npm:latest"
slugify: "npm:latest"
ts-py-datetime: "npm:latest"
checksum: 10c0/9c346ee9866f748b41d98dbefefd46ddb0a43f7d563e4456e000047e273e5441e5a15321ba8684325a81d746a9e9c32c5c0f4f1a58637291babebcae45329442
checksum: 10c0/f3953be5de5f27e7cf5c111bb9fc969e2e7a7732547c0549c88a5fed2480c12bdb058feff81e68059570831b1464cf26bf356df6f60dfcc904d16d2c6f844ee8
languageName: node
linkType: hard
@@ -10283,6 +10284,13 @@ __metadata:
languageName: node
linkType: hard
"slugify@npm:latest":
version: 1.6.9
resolution: "slugify@npm:1.6.9"
checksum: 10c0/8473c566ae00c5db26bfbf6182a4a9478ab3c912a9c926e1fdb410736a77228bfca4fdc5c755b46fafa7d2d9900de482fd7a9bd5e5c91128c4743c2c072d88da
languageName: node
linkType: hard
"smart-buffer@npm:^4.2.0":
version: 4.2.0
resolution: "smart-buffer@npm:4.2.0"