Skip to content

test breaks when switch import #781

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
theNewFlesh opened this issue Jun 29, 2018 · 8 comments
Closed

test breaks when switch import #781

theNewFlesh opened this issue Jun 29, 2018 · 8 comments

Comments

@theNewFlesh
Copy link

theNewFlesh commented Jun 29, 2018

Version

1.0.0-beta.18

Reproduction link

https://codepen.io/anon/pen/NzeOvE

Steps to reproduce

npm test

What is expected?

test to pass

What is actually happening?

test fails with:

FAILED TESTS:
  Timeline
    events
      ✖ onMarkerUpdate emits correct events and values
        PhantomJS 2.1.1 (Linux 0.0.0)
      TypeError: undefined is not an object (evaluating 'emitted.inPointChanged') in timeline.spec.ts (line 26903)
      timeline.spec.ts:26903:27
      <Jasmine>

When I switch the import from "vue-test-utils" to "@vue/test-utils" one of my tests breaks.

wrapper.emitted() resolves to undefined in the latter case, and I get an "TypeError: undefined is not an object" error

Given that:

  • it works in the former case but not in the latter
  • the wrapper API has not changed in any relevant ways
  • the only changes to my code is the import statement

it follows that it is something to do with @vue/test-utils itself.

@theNewFlesh
Copy link
Author

here is the component:

<template>
    <div ref="sliderContainer" class="slider-container" id="slider-container"></div>
</template>

<script lang="ts">
    import Vue from "vue";
    import { Component, Prop } from "vue-property-decorator";
    import "nouislider/distribute/nouislider.min.css";
    import * as noUiSlider from "nouislider";
    import * as utils from "../../../tools/utils";

    /*
    @param inPoint the position of the input (leftmost) marker
    @param playhead the default position of the playhead
    @param outPoint the position of the output (rightmost) marker
    @param step number of frames the playhead will step upon moving
    @param displayMarkers toggles display of input and output markers
    */
    @Component
    export default class Timeline extends Vue {

        @Prop({default: 0})
        public inPoint: number;

        @Prop({default: 0})
        public playhead: number;

        @Prop({default: 1000})
        public outPoint: number;

        @Prop({default: 1})
        public step: number;

        @Prop({default: true})
        public displayMarkers: boolean;

        private slider: noUiSlider;

        // These properties are needed for diffing noUiSlider event values
        private _inPoint: number;
        private _playhead: number;
        private _outPoint: number;

        /*
        @return tick step size relative to frame range
        */
        public get tickStep(): number {

            const delta: number = this._outPoint - this._inPoint;
            let tickSteps: number[] = utils.BASE_10_MARKERS.filter(
                (item) => (delta / item < 20)
            );
            return tickSteps[0];
        }

        /*
        @return frame range divided into (tickStep / 2) ticks
        */
        public get ticks(): number[] {
            return utils.range(
                this._inPoint,
                this._outPoint,
                this.tickStep / 2
            );
        }

        /*
        Splits noUiSlider update event into three events:
        - inPointChanged
        - playheadChanged
        - outPointChanged
        and emits them.
        @param event a marker update event to be processed
        @event inPointChanged in-point marker has been moved
        @event playheadChanged playhead marker has been moved
        @event outPointChanged out-point marker has been moved
        */
        public onMarkerUpdate(event) {
            // noUiSlider bundles all its update events in a single array
            // this method assumes three markers are present and decomposes
            // them into separate events

            event = event.map( (val) => Math.round(Number(val)) )
            const input: number = event[0];
            const playhead: number = event[1];
            const output: number = event[2];

            if (input != this._inPoint) {
                this._inPoint = input;
                this.$emit("inPointChanged", input);
            };

            if (playhead != this._playhead) {
                this._playhead = playhead;
                this.$emit("playheadChanged", playhead);
            };

            if (output != this._outPoint) {
                this._outPoint = output;
                this.$emit("outPointChanged", output);
            };
        }

        /*
        evaluates displayMarkers and toggles the display of the input and output markers
        */
        public toggleMarkers() {
            const container = this.$el as HTMLDivElement;
            const inpoint = container.querySelector(".noUi-handle.noUi-handle-lower");
            const outpoint = container.querySelector(".noUi-handle.noUi-handle-upper");

            if (!this.displayMarkers) {
                inpoint.setAttribute("style", "display: none");
                outpoint.setAttribute("style", "display: none");
            } else {
                inpoint.removeAttribute("style");
                outpoint.removeAttribute("style");
            };
        }

        /*
        assigns marker positions and errors on bad ones
        @throws Error if step not greater than 0
        @throws Error if tickStep is not greater than 0
        @throws Error if inPoint is less than outPoint
        */
        public created() {
            // these properties go undefined without assignment here
            this._inPoint = this.inPoint;
            this._playhead = this.playhead;
            this._outPoint = this.outPoint;

            if (this.step <= 0) {
                throw new Error("step must be greater than 0");
            };

            // TODO: determine if this is still needed
            if (this.tickStep <= 0) {
                throw new Error("tickStep must be greater than 0");
            };

            if (this._inPoint >= this._outPoint) {
                throw new Error(`inPoint must less than outPoint. ${this._inPoint} !< ${this._outPoint}`);
            };
        }

        /*
        build a noUISlider object and adds it to the DOM
        */
        public mounted() {
            const container = this.$refs.sliderContainer as HTMLDivElement;
            this.slider = noUiSlider.create(
                container,
                {
                    start: [this._inPoint, this._playhead, this._outPoint],
                    connect: [true, false, false, true],
                    step: this.step,
                    range: {
                        min: this._inPoint,
                        max: this._outPoint
                    },
                    pips: {
                        mode: "values",
                        values: this.ticks,
                        density: 1,
                        filter: (value, type) => value % this.tickStep ? 2: 1
                    }
                }
            );

            this.slider.on(
                "update",
                this.onMarkerUpdate
            );

            this.toggleMarkers();
        }
    }
</script>

<style lang="scss">
</style>

here is the test:

import Vue from "vue";
import Timeline from "../src/components/Timeline.vue";

import * as vtu from "@vue/test-utils";
import * as utils from "../../tools/utils";
// -----------------------------------------------------------------------------

/*
convenience function for getting a good timeline instance
@return a wrapped Timeline mounted with easily testable prop data
*/
function getWrapper1(): any {
    return vtu.mount(Timeline,
        {
            propsData: {
                inPoint: 2,
                outPoint: 6,
                step: 2,
                displayMarkers: true
            }
        }
    );
}

/*
like getWrapper1, but with props that make testing tick and tickStep easy
@return a wrapped Timeline mounted with easily testable prop data
*/
function getWrapper2(): any {
    return vtu.mount(Timeline,
        {
            propsData: {
                inPoint: 0,
                outPoint: 100,
                step: 1,
                displayMarkers: true
            }
        }
    );
}
// -----------------------------------------------------------------------------

describe('Timeline', () => {
    describe("events", () => {
        const wrapper = getWrapper1();

        it("onMarkerUpdate emits correct events and values", () => {
            wrapper.vm.onMarkerUpdate(["1", "2", "3"]);
            const emitted = wrapper.emitted();
            expect(emitted.inPointChanged[0][0]).toBe(1);
            expect(emitted.playheadChanged[0][0]).toBe(2);
            expect(emitted.outPointChanged[0][0]).toBe(3);
        });
    });
});

@eddyerburgh
Copy link
Member

Hi, sorry for the bug. Are you using the latest version (1.0.0-beta.20)?

The example you've posted is too large for me to debug, and I need to know other details (like @vue/test-utils version). Can you make a minimal reproduction in code sand box using the example template?

@theNewFlesh
Copy link
Author

No 1.0.0-beta.18

@theNewFlesh
Copy link
Author

I don't know how to run jasmine tests on codepen

@theNewFlesh
Copy link
Author

I've edited the pen as much as I can

@theNewFlesh
Copy link
Author

The point is wrapper.emitted() returns undefined when using @vue/test-utils instead of what it is supposed to

@eddyerburgh
Copy link
Member

Yes, but we have tests for wrapper.emitted, so it doesn't return undefined in all circumstances.

Can you try updating to beta.20 to see if the bug persists?

If not, please create a minimal repo in a GitHub repository, or in codesandbox—https://codesandbox.io/s/m4qk02vjoy.

@eddyerburgh
Copy link
Member

There's already an issue open for emitted being undefined, so I'll close this in favor of that issue: #819

I'm working on a fix that will be out soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants