Выдать исключение из компонента Vue и предотвратить дальнейшую обработку - PullRequest
0 голосов
/ 02 июля 2018

Я пишу компоненты Vue, и я хотел бы вызвать исключение, если одно из свойств отсутствует или недействительно, также я хотел бы запретить Vue отображать шаблон и прекратить дальнейшую обработку до точки, где шаблон не будет обработан и окончательно добавлен в DOM.

Итак, вот уменьшенная версия одного из написанных мной компонентов:

<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";

@Component({
    components: {}
})
export default class Checkbox extends Vue {
    @Prop() public id?: string;

    public mounted() {
        if (this.id == null) {
            this.$el.remove();
            throw new Error("The id property is missing.");
        }
    }
}
</script>

Теперь это работает, но у него есть недостаток, потому что он требует удаления элемента из DOM, и это затрудняет тестирование по следующим причинам:

  1. Когда компонент монтируется без идентификатора, он генерирует исключение, как я и предполагал.

  2. Поскольку я выбрасываю исключение из метода ловушки жизненного цикла mounted, я не могу смонтировать компонент и получить экземпляр, чтобы проверить, был ли удален элемент, и в некоторой степени это не имеет смысла для меня.

Вот фактический тест:

describe("When the id property is not assigned", () => {
    it("then the checkbox should throw an exception", () => {
        expect(() => shallowMount(Checkbox)).to.throw(); // works fine as expected.
    });

    it("then the checkbox should not exist", () => {
        const wrapper: VueWrapper = shallowMount(Checkbox); // throws because we didn't provide any id, again, as expected.

        /* This is what I would like to do but I don't get an instance back so obviously I can't do it. */
        const checkbox = wrapper.vm.$el; 
        expect(checkbox).to.not.exist;
    });
});

Я пытался вызвать исключение из метода created ловушки жизненного цикла, а не mounted, но это не мешает Vue добавить элемент в DOM.

Просто чтобы уточнить, я написал в тесте, что «это то, что я хотел бы сделать», но на самом деле я бы предпочел не удалять элемент вообще и предотвращать любую вставку визуализированного компонента в DOM, таким образом Мне даже не нужно было бы проверять это.

Ответы [ 3 ]

0 голосов
/ 03 июля 2018

Мое предыдущее решение было излишним, и я действительно задумался над тем, что в итоге я сделал, удалив элемент, когда обязательное свойство не предоставлено, например:

<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";

@Component
export default class Checkbox extends Vue {
    @Prop({ required: true })
    public id?: string;

    public mounted() {
        if (this.id == null) {
            this.$el.remove();
            return;
        }

        // ...
    }
}
</script>

Наконец, тесты, которые я написал для этого, следующие:

describe("When the id property is not provided", () => {
    let wrapper: VueWrapper;

    beforeEach(() => {
        wrapper = shallowMount(Checkbox, {
            attachToDocument: true
        });
    });

    it("and is required", () => {
        const id = (wrapper.vm.$options.props as any).id;
        expect(id.required).to.be.true;
    });

    it("then the input element should not exist in the DOM", () => {
        const exists = document.body.contains(wrapper.element);
        expect(exists).to.be.false;
    });
});
0 голосов
/ 10 июля 2018

Мои две предыдущие попытки были неудачными из-за несоответствия в моих компонентах, и я все еще хотел реализовать первоначальную идею, поэтому я сделал следующее:

Я создал собственный класс исключений с именем DismountException, который выглядит примерно так:

import { Exception } from "./exception";

export class DismountException extends Exception {
    constructor(public readonly element: HTMLElement, message: string) {
        super(message);
        element.remove();
    }
}

и затем в моем компоненте я просто выбрасываю это исключение, при возникновении ошибки он удаляет элемент со страницы.

Это разделение интересов позволяет мне тестировать исключение отдельно от любого компонента, и что оно фактически удаляет элемент из DOM, и в моих компонентах единственное, что мне нужно проверить, это то, выдают ли они это конкретное исключение, таким образом, я могу гарантировать два помещения:

  1. Если установлен неисправный компонент, он должен выбросить, чтобы остановить любую обработку.

  2. Когда выдается исключение, он должен удалить элемент со страницы.

0 голосов
/ 03 июля 2018

Мне удалось заставить это работать так, как я хочу, переопределив errorHandler следующим образом:

Vue.config.errorHandler = (err, vm, info) => {
    console.error(info);
    console.error(err);
    if (vm.$options != null && vm.$options.props != null && vm.$el instanceof HTMLElement) {
        for (const key in vm.$options.props) {
            if (vm.$options.props.hasOwnProperty(key)) {
                const prop = (vm.$options.props as any)[key];
                if (prop.required) {
                    vm.$el.remove();
                    break;
                }
            }
        }
    }
};

Реализация флажка выглядит следующим образом:

<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";

@Component
export default class Checkbox extends Vue {
    @Prop({ required: true })
    public id?: string;

    public mounted() {
        if (this.id == null) {
            throw new Error();
        }

        // ...
    }
}
</script>

И, наконец, поскольку удаление элемента больше не относится к компоненту, тест был упрощен и выглядит следующим образом:

describe("When the id property is not assigned", () => {
    it("then the checkbox should throw an exception", () => {
        expect(() => shallowMount(Checkbox)).to.throw();
    });
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...