Testing

Install the test runner

Use Vitest and Angular Native Testing Library to exercise your chart in Node. Install the same version of @ng-native/testing as the @ng-native packages in your app.

npm install --save-dev @ng-native/testing@0.19.1 vitest@5

Configure Vitest for Angular Native

The Angular Native plugin loads the native testing stand-ins and links the compiled Charts package for the test runner.

import {ngNative} from '@ng-native/testing/vitest';
import {defineConfig} from 'vitest/config';

export default defineConfig({
  plugins: [ngNative({inline: ['@neural-charts/native']})],
  test: {include: ['src/**/*.test.ts']},
});

Test selection, the legend and invalid data

The first test reads the tooltip and verifies the point identity in interactionChange. The second checks that navigation skips a hidden series and includes it again after restoring it. The third passes a point in an unknown category and verifies planningError.

  • The test supplies a layout event because Node has no native screen to measure. The English locale fixes the accessible control names, and the example disables animations and haptics for repeatable assertions.
import {cleanup, fireEvent, render, screen, userEvent} from '@ng-native/testing';
import {afterEach, expect, test} from 'vitest';
import {
  NativeDataChart,
  type InteractionSnapshot,
  type NativeChartDiagnostic,
  type NativeChartOptions,
  type NativeLineData,
} from '@neural-charts/native';

afterEach(cleanup);

const data = {
  type: 'line',
  axes: {
    x: {type: 'category', values: [{id: 'mon', label: 'Mon'}]},
    y: {type: 'linear'},
  },
  series: [
    {id: 'this-week', name: 'This week', data: [{id: 'mon', x: 'mon', y: 29}]},
    {id: 'last-week', name: 'Last week', data: [{id: 'mon', x: 'mon', y: 20}]},
  ],
} as const satisfies NativeLineData;

const options = {
  appearance: {locale: 'en'},
  format: {unit: 'visits'},
  legend: {visible: true, interactive: true},
  animation: {enabled: false},
  interaction: {selectionControls: true, haptics: false},
} as const satisfies NativeChartOptions<'line'>;

async function renderChart(events: InteractionSnapshot[]) {
  const result = await render(NativeDataChart, {
    inputs: {data, options},
    on: {interactionChange: event => events.push(event)},
  });
  fireEvent(screen.getByTestId('native-chart-plot'), 'layout', {
    nativeEvent: {layout: {x: 0, y: 0, width: 400, height: 300}},
  });
  await result.detectChanges();
  return result;
}

test('reads the selected value and emits its stable identity', async () => {
  const events: InteractionSnapshot[] = [];
  await renderChart(events);

  await userEvent.setup().press(screen.getByRole('button', {name: 'Next observation'}));

  expect(screen.getByText('29 visits')).toBeTruthy();
  expect(events.at(-1)?.selected).toEqual({seriesId: 'this-week', pointId: 'mon'});
});

test('skips a hidden series and restores it from the legend', async () => {
  const events: InteractionSnapshot[] = [];
  const chart = await renderChart(events);
  const user = userEvent.setup();
  const press = (name: string) => user.press(screen.getByRole('button', {name}));

  await press('Hide This week');
  expect(chart.instance.hiddenSeriesIds()).toEqual(['this-week']);
  await press('Next observation');
  expect(screen.getByText('20 visits')).toBeTruthy();
  expect(events.at(-1)?.selected).toEqual({seriesId: 'last-week', pointId: 'mon'});

  await press('Show This week');
  expect(chart.instance.hiddenSeriesIds()).toEqual([]);
  await press('Clear selection');
  await press('Next observation');
  expect(screen.getByText('29 visits')).toBeTruthy();
  expect(events.at(-1)?.selected).toEqual({seriesId: 'this-week', pointId: 'mon'});
});

test('emits a diagnostic when a point uses an unknown category', async () => {
  const errors: NativeChartDiagnostic[] = [];
  const invalidData = {
    ...data,
    series: [{id: 'this-week', name: 'This week', data: [{id: 'mon', x: 'unknown', y: 29}]}],
  } as const satisfies NativeLineData;

  await render(NativeDataChart, {
    inputs: {data: invalidData, options},
    on: {planningError: error => errors.push(error)},
  });

  expect(errors).toEqual(expect.arrayContaining([
    expect.objectContaining({reason: 'UNKNOWN_CATEGORY', path: 'series[0].data[0].x'}),
  ]));
});

Run the tests

These tests check the component in Node. Use an iOS or Android app to verify real touch gestures, screen readers and haptics.

npx vitest run src/chart.test.ts