Commit 871518a8 authored by Paul Gascou-Vaillancourt's avatar Paul Gascou-Vaillancourt Committed by Miguel Rincon

Add helpers to init GlToggle instances

This adds a shared HAML partial as well as a Javascript that can be used
to instantiate GlToggle instances in HAML views.
The pages that render the partial must import the initToggle helper and
call it with the appropriate DOM node.
parent 0cd5c848
import { kebabCase } from 'lodash';
import Vue from 'vue';
import { GlToggle } from '@gitlab/ui';
import { parseBoolean } from '~/lib/utils/common_utils';
export const initToggle = (el) => {
if (!el) {
return false;
}
const {
name,
isChecked,
disabled,
isLoading,
label,
help,
labelPosition,
...dataset
} = el.dataset;
return new Vue({
el,
props: {
disabled: {
type: Boolean,
required: false,
default: parseBoolean(disabled),
},
isLoading: {
type: Boolean,
required: false,
default: parseBoolean(isLoading),
},
},
data() {
return {
value: parseBoolean(isChecked),
};
},
render(h) {
return h(GlToggle, {
props: {
name,
value: this.value,
disabled: this.disabled,
isLoading: this.isLoading,
label,
help,
labelPosition,
},
class: el.className,
attrs: Object.fromEntries(
Object.entries(dataset).map(([key, value]) => [`data-${kebabCase(key)}`, value]),
),
on: {
change: (newValue) => {
this.value = newValue;
this.$emit('change', newValue);
},
},
});
},
});
};
-# This partial renders a GlToggle root element.
-# To actually initialize the component, make sure to call the initToggle helper from ~/toggles.
- classes = local_assigns.fetch(:classes)
- name = local_assigns.fetch(:name, nil)
- is_checked = local_assigns.fetch(:is_checked, false).to_s
- disabled = local_assigns.fetch(:disabled, false).to_s
- is_loading = local_assigns.fetch(:is_loading, false).to_s
- label = local_assigns.fetch(:label, nil)
- help = local_assigns.fetch(:help, nil)
- label_position = local_assigns.fetch(:label_position, nil)
- data = local_assigns.fetch(:data, {})
%span{ class: classes,
data: { name: name,
is_checked: is_checked,
disabled: disabled,
is_loading: is_loading,
label: label,
help: help,
label_position: label_position,
**data } }
-# Leverage this block to render a rich help text. To render a plain text help text,
-# prefer the `help` parameter.
- if yield.present?
.gl-text-secondary.gl-mt-1
= yield
import { createWrapper } from '@vue/test-utils';
import { GlToggle } from '@gitlab/ui';
import { initToggle } from '~/toggles';
// Selectors
const TOGGLE_WRAPPER_CLASS = '.gl-toggle-wrapper';
const TOGGLE_LABEL_CLASS = '.gl-toggle-label';
const CHECKED_CLASS = '.is-checked';
const DISABLED_CLASS = '.is-disabled';
const LOADING_CLASS = '.toggle-loading';
const HELP_TEXT_SELECTOR = '[data-testid="toggle-help"]';
// Toggle settings
const toggleClassName = 'js-custom-toggle-class';
const toggleLabel = 'Toggle label';
describe('toggles/index.js', () => {
let instance;
let toggleWrapper;
const createRootEl = (dataAttrs) => {
const dataset = {
label: toggleLabel,
...dataAttrs,
};
const el = document.createElement('span');
el.classList.add(toggleClassName);
Object.entries(dataset).forEach(([key, value]) => {
el.dataset[key] = value;
});
document.body.appendChild(el);
return el;
};
const initToggleWithOptions = (options = {}) => {
const el = createRootEl(options);
instance = initToggle(el);
toggleWrapper = document.querySelector(TOGGLE_WRAPPER_CLASS);
};
afterEach(() => {
document.body.innerHTML = '';
instance = null;
toggleWrapper = null;
});
describe('initToggle', () => {
describe('default state', () => {
beforeEach(() => {
initToggleWithOptions();
});
it('attaches a GlToggle to the element', async () => {
expect(toggleWrapper).not.toBe(null);
expect(toggleWrapper.querySelector(TOGGLE_LABEL_CLASS).textContent).toBe(toggleLabel);
});
it('passes CSS classes down to GlToggle', () => {
expect(toggleWrapper.className).toContain(toggleClassName);
});
it('is not checked', () => {
expect(toggleWrapper.querySelector(CHECKED_CLASS)).toBe(null);
});
it('is enabled', () => {
expect(toggleWrapper.querySelector(DISABLED_CLASS)).toBe(null);
});
it('is not loading', () => {
expect(toggleWrapper.querySelector(LOADING_CLASS)).toBe(null);
});
it('emits "change" event when value changes', () => {
const wrapper = createWrapper(instance);
const event = 'change';
const listener = jest.fn();
instance.$on(event, listener);
expect(listener).toHaveBeenCalledTimes(0);
wrapper.find(GlToggle).vm.$emit(event, true);
expect(listener).toHaveBeenCalledTimes(1);
expect(listener).toHaveBeenLastCalledWith(true);
wrapper.find(GlToggle).vm.$emit(event, false);
expect(listener).toHaveBeenCalledTimes(2);
expect(listener).toHaveBeenLastCalledWith(false);
});
});
describe('with custom options', () => {
const name = 'toggle-name';
const help = 'Help text';
const foo = 'bar';
beforeEach(() => {
initToggleWithOptions({
name,
isChecked: true,
disabled: true,
isLoading: true,
help,
labelPosition: 'hidden',
foo,
});
toggleWrapper = document.querySelector(TOGGLE_WRAPPER_CLASS);
});
it('sets the custom name', () => {
const input = toggleWrapper.querySelector('input[type="hidden"]');
expect(input.name).toBe(name);
});
it('is checked', () => {
expect(toggleWrapper.querySelector(CHECKED_CLASS)).not.toBe(null);
});
it('is disabled', () => {
expect(toggleWrapper.querySelector(DISABLED_CLASS)).not.toBe(null);
});
it('is loading', () => {
expect(toggleWrapper.querySelector(LOADING_CLASS)).not.toBe(null);
});
it('sets the custom help text', () => {
expect(toggleWrapper.querySelector(HELP_TEXT_SELECTOR).textContent).toBe(help);
});
it('hides the label', () => {
expect(
toggleWrapper.querySelector(TOGGLE_LABEL_CLASS).classList.contains('gl-sr-only'),
).toBe(true);
});
it('passes custom dataset to the wrapper', () => {
expect(toggleWrapper.dataset.foo).toBe('bar');
});
});
});
});
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'shared/_gl_toggle.html.haml' do
context 'defaults' do
before do
render partial: 'shared/gl_toggle', locals: {
classes: '.js-gl-toggle'
}
end
it 'does not set a name' do
expect(rendered).not_to have_selector('[data-name]')
end
it 'sets default is-checked attributes' do
expect(rendered).to have_selector('[data-is-checked="false"]')
end
it 'sets default disabled attributes' do
expect(rendered).to have_selector('[data-disabled="false"]')
end
it 'sets default is-loading attributes' do
expect(rendered).to have_selector('[data-is-loading="false"]')
end
it 'does not set a label' do
expect(rendered).not_to have_selector('[data-label]')
end
it 'does not set a label position' do
expect(rendered).not_to have_selector('[data-label-position]')
end
end
context 'with custom options' do
before do
render partial: 'shared/gl_toggle', locals: {
classes: 'js-custom-gl-toggle',
name: 'toggle-name',
is_checked: true,
disabled: true,
is_loading: true,
label: 'Custom label',
label_position: 'top',
data: {
foo: 'bar'
}
}
end
it 'sets the custom class' do
expect(rendered).to have_selector('.js-custom-gl-toggle')
end
it 'sets the custom name' do
expect(rendered).to have_selector('[data-name="toggle-name"]')
end
it 'sets the custom is-checked attributes' do
expect(rendered).to have_selector('[data-is-checked="true"]')
end
it 'sets the custom disabled attributes' do
expect(rendered).to have_selector('[data-disabled="true"]')
end
it 'sets the custom is-loading attributes' do
expect(rendered).to have_selector('[data-is-loading="true"]')
end
it 'sets the custom label' do
expect(rendered).to have_selector('[data-label="Custom label"]')
end
it 'sets the cutom label position' do
expect(rendered).to have_selector('[data-label-position="top"]')
end
it 'sets cutom data attributes' do
expect(rendered).to have_selector('[data-foo="bar"]')
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment