apexcharts / ng-apexcharts

ng-apexcharts is an implementation of apexcharts for angular. It comes with one simple component that enables you to use apexcharts in an angular project.
MIT License
310 stars 78 forks source link

Charts break unit tests #291

Closed marianatuma closed 6 months ago

marianatuma commented 8 months ago

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 8 months ago

You can check this out, I had the same problem and this solved it https://github.com/apexcharts/react-apexcharts/issues/425#issuecomment-1734488077

Aalnius commented 8 months ago

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, } };

marianatuma commented 8 months ago

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 />',
}));
marianatuma commented 8 months ago

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 7 months ago

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 7 months ago

@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: () => {}
      })
    });

  });
marianatuma commented 6 months ago

Thank you!