apexcharts/ng-apexcharts

Charts break unit tests

marianatuma opened this issue · 7 comments

I have a very simple component that renders a bar chart, and it breaks the unit tests.

The component:

Component({
  selector: 'hu-bar-chart',
  standalone: true,
  imports: [CommonModule, NgApexchartsModule],
  templateUrl: './bar-chart.component.html',
  styleUrls: ['./bar-chart.component.scss'],
})
export class BarChartComponent implements OnChanges {
  series: ApexAxisChartSeries | ApexNonAxisChartSeries;
  xAxis: ApexXAxis;
  chart: ApexChart;
  title: ApexTitleSubtitle;

  @Input() surveyQuestionData: SurveyQuestionData;

  constructor() {
    this.xAxis = {};

    this.surveyQuestionData = {
      internal: {},
      label: { 'en-US': '' },
    };
    this.title = {};

    this.series = [
      {
        name: 'Leaders',
        data: [355, 390, 300, 350, 390, 180, 355, 390],
        color: '#5D87FF',
      },
      {
        name: 'Employees',
        data: [280, 250, 325, 215, 250, 310, 280, 250],
        color: '#49BEFF',
      },
    ];

    this.chart = {
      type: 'bar',
      height: 390,
      offsetX: -15,
      toolbar: { show: true },
      foreColor: '#adb0bb',
      fontFamily: 'inherit',
      sparkline: { enabled: false },
    };
  }
}

The component's html file:

<apx-chart
  test-id="bar-chart"
  [series]="series"
  [chart]="chart"
  [xaxis]="xAxis"
></apx-chart>

The spec.ts file:


describe('BarChartComponent', () => {
  let component: BarChartComponent;
  let fixture: ComponentFixture<BarChartComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [BarChartComponent],
    }).compileComponents();

    fixture = TestBed.createComponent(BarChartComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

And the error (abridged for readability):

console.error
Error during cleanup of component {
  component: BarChartComponent {
   ...
    __ngContext__: 0
  },
  stacktrace: TypeError: Cannot read properties of undefined (reading 'node')
      at t.value (/home/<path>/node_modules/apexcharts/dist/apexcharts.common.js:14:20569)
      at t.value (/home/<path>/node_modules/apexcharts/dist/apexcharts.common.js:14:20309)
      at t.value (/home/<path>/node_modules/apexcharts/dist/apexcharts.common.js:14:40953)
      at ChartComponent.ngOnDestroy (/home/<path>/node_modules/ng-apexcharts/fesm2015/ng-apexcharts.mjs:23:27)
      at executeOnDestroys (/home/<path>/node_modules/@angular/core/fesm2022/core.mjs:7359:32)
      at cleanUpView (/home/<path>/node_modules/@angular/core/fesm2022/core.mjs:7267:9)
      at destroyViewTree (/home/<path>/node_modules/@angular/core/fesm2022/core.mjs:7095:21)
      at destroyLView (/home/<path>/node_modules/@angular/core/fesm2022/core.mjs:7245:9)
      at RootViewRef.destroy (/home/<path>/node_modules/@angular/core/fesm2022/core.mjs:13738:9)
      at ComponentRef.destroy (/home/<path>/node_modules/@angular/core/fesm2022/core.mjs:14195:23)
      at ComponentFixture.destroy (/home/<path>/node_modules/@angular/core/fesm2022/testing.mjs:214:31)
      at /home/<path>/node_modules/@angular/core/fesm2022/testing.mjs:27549:25
      at Array.forEach (<anonymous>)
      ...
}
...

● BarChartComponent › should create

1 component threw errors during cleanup

  at _TestBedImpl.destroyActiveFixtures (../../node_modules/@angular/core/fesm2022/testing.mjs:27561:19)
  at _TestBedImpl.resetTestingModule (../../node_modules/@angular/core/fesm2022/testing.mjs:27373:18)
  at ../../node_modules/@angular/core/fesm2022/testing.mjs:27713:21
  at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (../../node_modules/zone.js/bundles/zone.umd.js:411:30)
  at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (../../node_modules/zone.js/bundles/zone-testing.umd.js:300:43)
  at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (../../node_modules/zone.js/bundles/zone.umd.js:410:56)
  at Zone.Object.<anonymous>.Zone.run (../../node_modules/zone.js/bundles/zone.umd.js:165:47)
  at Object.wrappedFunc (../../node_modules/zone.js/bundles/zone-testing.umd.js:789:34)
Xapuu commented

You can check this out, I had the same problem and this solved it apexcharts/react-apexcharts#425 (comment)

I had the same problem with bar charts I ended up having to disable animations for the tests by setting the property on the global apex object before running the tests.
(global as any).Apex.chart = { animations: { enabled: false, } };

I had the same problem with bar charts I ended up having to disable animations for the tests by setting the property on the global apex object before running the tests. (global as any).Apex.chart = { animations: { enabled: false, } };

Thanks so much for replying! Just a note, the name Apex is undefined for me:

 TypeError: Cannot set properties of undefined (setting 'chart')

      13 |
      14 | global.TextEncoder = TextEncoder;
    > 15 | (global as any).Apex.chart = { animations: { enabled: false } };

You can check this out, I had the same problem and this solved it apexcharts/react-apexcharts#425 (comment)

This fixed my issue. In case someone else finds this question and is working on angular, I put the following in test-setup.ts:

jest.mock('ng-apexcharts', () => ({
  __esModule: true,
  default: () => '<div />',
}));

My bad, I closed this issue too soon.

The solution I thought was working actually threw this error (abridged for readability):

 FAIL   core  apps/core/src/app/components/bar-chart/bar-chart.component.spec.ts
  BarChartComponent
    ✕ should create (187 ms)

  ● BarChartComponent › should create

    TypeError: Cannot read properties of undefined (reading 'ɵcmp')

      10 |
      11 |   beforeEach(async () => {
    > 12 |     await TestBed.configureTestingModule({
         |                   ^
      13 |       imports: [BarChartComponent],
      14 |     }).compileComponents();
      15 |

      at getComponentDef (../../node_modules/@angular/core/fesm2022/testing.mjs:27091:18)
      at isStandaloneComponent (../../node_modules/@angular/core/fesm2022/testing.mjs:27087:17)
      at ../../node_modules/@angular/core/fesm2022/testing.mjs:26856:29
          at Array.forEach (<anonymous>)
     ...
egiev commented

My bad, I closed this issue too soon.

The solution I thought was working actually threw this error (abridged for readability):

 FAIL   core  apps/core/src/app/components/bar-chart/bar-chart.component.spec.ts
  BarChartComponent
    ✕ should create (187 ms)

  ● BarChartComponent › should create

    TypeError: Cannot read properties of undefined (reading 'ɵcmp')

      10 |
      11 |   beforeEach(async () => {
    > 12 |     await TestBed.configureTestingModule({
         |                   ^
      13 |       imports: [BarChartComponent],
      14 |     }).compileComponents();
      15 |

      at getComponentDef (../../node_modules/@angular/core/fesm2022/testing.mjs:27091:18)
      at isStandaloneComponent (../../node_modules/@angular/core/fesm2022/testing.mjs:27087:17)
      at ../../node_modules/@angular/core/fesm2022/testing.mjs:26856:29
          at Array.forEach (<anonymous>)
     ...

Did you find any solution?
I faced the same issue.

Frotty commented

@egiev Solution is in linked issue, add this to the test

beforeEach(async () => {
    Object.defineProperty(window, 'ResizeObserver', {
      writable: true,
      value:
        window.ResizeObserver ||
        jest.fn().mockImplementation(() => ({
          observe: jest.fn(),
          unobserve: jest.fn(),
          disconnect: jest.fn()
        }))
    });

    Object.defineProperty(global.SVGElement.prototype, 'getScreenCTM', {
      writable: true,
      value: jest.fn()
    });

    Object.defineProperty(global.SVGElement.prototype, 'createSVGMatrix', {
      writable: true,
      value: jest.fn().mockReturnValue({
        x: 10,
        y: 10,
        // eslint-disable-next-line @typescript-eslint/no-empty-function
        inverse: () => {},
        // eslint-disable-next-line @typescript-eslint/no-empty-function
        multiply: () => {}
      })
    });

  });

Thank you!