Change 'revert' button to title case

- Switch 'revert' button text to title case for consistency and more
  formal and professional look.
- Update related styles to reflect the new case usage.
- Adjust tests to match the new button label casing.
- Remove reduntant visibility switch between to elements to simpify the
  DOM and style rules.
This commit is contained in:
undergroundwires
2024-02-01 17:20:11 +01:00
parent 4da306b9f7
commit 937f4593d1
4 changed files with 60 additions and 49 deletions

View File

@@ -2,7 +2,7 @@
<ToggleSwitch <ToggleSwitch
v-model="isReverted" v-model="isReverted"
:stop-click-propagation="true" :stop-click-propagation="true"
:label="'revert'" :label="'Revert'"
/> />
</template> </template>

View File

@@ -10,8 +10,15 @@
> >
<div class="toggle-animation"> <div class="toggle-animation">
<div class="circle" /> <div class="circle" />
<span class="label-off">{{ label }}</span> <span
<span class="label-on">{{ label }}</span> class="label"
:class="{
'label-off': !isChecked,
'label-on': isChecked,
}"
>
{{ label }}
</span>
</div> </div>
</div> </div>
</template> </template>
@@ -91,16 +98,6 @@ $gap : 0.25em;
} }
} }
@mixin setVisibility($isVisible: true) {
@if $isVisible {
display: block;
opacity: 1;
} @else {
display: none;
opacity: 0;
}
}
.toggle-switch { .toggle-switch {
display: flex; display: flex;
overflow: hidden; overflow: hidden;
@@ -155,34 +152,22 @@ $gap : 0.25em;
left: $padded-left-offset; left: $padded-left-offset;
background-color: $color-toggle-checked; background-color: $color-toggle-checked;
} }
}
.label-off { .label {
@include setVisibility(false); font-weight: bold;
transition: all 0.3s ease-out, color 0s;
&.label-off {
@include locateNearCircle('left');
padding-right: $padding-horizontal;
} }
.label-on { &.label-on {
@include setVisibility(true); color: $color-text-checked;
@include locateNearCircle('right');
padding-left: $padding-horizontal;
} }
} }
.label-off, .label-on {
text-transform: uppercase;
font-weight: 700;
transition: all 0.3s ease-out;
}
.label-off {
@include setVisibility(true);
@include locateNearCircle('left');
padding-right: $padding-horizontal;
}
.label-on {
@include setVisibility(false);
color: $color-text-checked;
@include locateNearCircle('right');
padding-left: $padding-horizontal;
}
} }
</style> </style>

View File

@@ -1,4 +1,5 @@
import { expectExists } from '@tests/shared/Assertions/ExpectExists'; import { expectExists } from '@tests/shared/Assertions/ExpectExists';
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';
import { openCard } from './support/interactions/card'; import { openCard } from './support/interactions/card';
describe('revert toggle', () => { describe('revert toggle', () => {
@@ -21,7 +22,7 @@ describe('revert toggle', () => {
it('should have revert label', () => { it('should have revert label', () => {
cy.get('@toggleSwitch') cy.get('@toggleSwitch')
.find('span') .find('span')
.contains('revert'); .contains('revert', { matchCase: false });
}); });
it('should render label completely without clipping', () => { // Regression test for a bug where label is partially rendered (clipped) it('should render label completely without clipping', () => { // Regression test for a bug where label is partially rendered (clipped)
@@ -34,7 +35,11 @@ describe('revert toggle', () => {
const expectedMinimumTextWidth = getTextWidth(text, font); const expectedMinimumTextWidth = getTextWidth(text, font);
const containerWidth = $label.parent().width(); const containerWidth = $label.parent().width();
expectExists(containerWidth); expectExists(containerWidth);
expect(expectedMinimumTextWidth).to.be.lessThan(containerWidth); expect(expectedMinimumTextWidth).to.be.lessThan(containerWidth, formatAssertionMessage([
'Label is not rendered completely.',
`Expected minimum text width: ${expectedMinimumTextWidth}`,
`Actual text container width: ${containerWidth}`,
]));
}); });
}); });

View File

@@ -5,15 +5,19 @@ import {
} from '@vue/test-utils'; } from '@vue/test-utils';
import { nextTick, defineComponent } from 'vue'; import { nextTick, defineComponent } from 'vue';
import ToggleSwitch from '@/presentation/components/Scripts/View/Tree/NodeContent/ToggleSwitch.vue'; import ToggleSwitch from '@/presentation/components/Scripts/View/Tree/NodeContent/ToggleSwitch.vue';
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';
const DOM_INPUT_TOGGLE_CHECKBOX_SELECTOR = 'input.toggle-input'; const DOM_INPUT_TOGGLE_CHECKBOX_SELECTOR = 'input.toggle-input';
const DOM_INPUT_TOGGLE_LABEL_OFF_SELECTOR = 'span.label-off'; const DOM_INPUT_TOGGLE_LABEL_OFF_SELECTOR = '.label-off';
const DOM_INPUT_TOGGLE_LABEL_ON_SELECTOR = 'span.label-on'; const DOM_INPUT_TOGGLE_LABEL_ON_SELECTOR = '.label-on';
const DOM_INPUT_CIRCLE_ICON_SELECTOR = '.circle'; const DOM_INPUT_CIRCLE_ICON_SELECTOR = '.circle';
describe('ToggleSwitch.vue', () => { describe('ToggleSwitch.vue', () => {
describe('initial state', () => { describe('initial state', () => {
const testCases = [ const testScenarios: ReadonlyArray<{
readonly description: string;
readonly initialValue: boolean;
}> = [
{ {
initialValue: false, initialValue: false,
description: 'unchecked for false', description: 'unchecked for false',
@@ -23,7 +27,7 @@ describe('ToggleSwitch.vue', () => {
description: 'checked for true', description: 'checked for true',
}, },
]; ];
testCases.forEach(({ initialValue, description }) => { testScenarios.forEach(({ initialValue, description }) => {
it(`renders as ${description}`, () => { it(`renders as ${description}`, () => {
// arrange // arrange
const expectedState = initialValue; const expectedState = initialValue;
@@ -42,17 +46,23 @@ describe('ToggleSwitch.vue', () => {
}); });
}); });
describe('label rendering', () => { describe('label rendering', () => {
const testCases = [ const testScenarios: ReadonlyArray<{
readonly description: string;
readonly initialValue: boolean;
readonly selector: string;
}> = [
{ {
description: 'off label', description: 'off label',
initialValue: false,
selector: DOM_INPUT_TOGGLE_LABEL_OFF_SELECTOR, selector: DOM_INPUT_TOGGLE_LABEL_OFF_SELECTOR,
}, },
{ {
description: 'on label', description: 'on label',
initialValue: true,
selector: DOM_INPUT_TOGGLE_LABEL_ON_SELECTOR, selector: DOM_INPUT_TOGGLE_LABEL_ON_SELECTOR,
}, },
]; ];
testCases.forEach(({ selector, description }) => { testScenarios.forEach(({ selector, initialValue, description }) => {
it(description, () => { it(description, () => {
// arrange // arrange
const expectedLabel = 'expected-test-label'; const expectedLabel = 'expected-test-label';
@@ -61,18 +71,26 @@ describe('ToggleSwitch.vue', () => {
const wrapper = mountComponent({ const wrapper = mountComponent({
properties: { properties: {
label: expectedLabel, label: expectedLabel,
modelValue: initialValue,
}, },
}); });
// assert // assert
const element = wrapper.find(selector); const element = wrapper.find(selector);
expect(element.exists()).to.equal(true, formatAssertionMessage([
`Selector "${selector}" could not find the DOM element`,
`HTML:\n${wrapper.html()}`,
]));
expect(element.text()).to.equal(expectedLabel); expect(element.text()).to.equal(expectedLabel);
}); });
}); });
}); });
describe('model updates', () => { describe('model updates', () => {
describe('emission on change', () => { describe('emission on change', () => {
const testCases = [ const testScenarios: ReadonlyArray<{
readonly initialValue: boolean;
readonly newCheckValue: boolean;
}> = [
{ {
initialValue: true, initialValue: true,
newCheckValue: false, newCheckValue: false,
@@ -82,7 +100,7 @@ describe('ToggleSwitch.vue', () => {
newCheckValue: true, newCheckValue: true,
}, },
]; ];
testCases.forEach(({ initialValue, newCheckValue }) => { testScenarios.forEach(({ initialValue, newCheckValue }) => {
it(`emits ${newCheckValue} when initial value is ${initialValue} and checkbox value changes`, async () => { it(`emits ${newCheckValue} when initial value is ${initialValue} and checkbox value changes`, async () => {
// arrange // arrange
const wrapper = mountComponent({ const wrapper = mountComponent({
@@ -102,7 +120,10 @@ describe('ToggleSwitch.vue', () => {
}); });
}); });
describe('no emission on identical value', () => { describe('no emission on identical value', () => {
const testCases = [ const testScenarios: ReadonlyArray<{
readonly description: string;
readonly value: boolean;
}> = [
{ {
value: true, value: true,
description: 'true', description: 'true',
@@ -112,7 +133,7 @@ describe('ToggleSwitch.vue', () => {
description: 'false', description: 'false',
}, },
]; ];
testCases.forEach(({ value, description }) => { testScenarios.forEach(({ value, description }) => {
it(`does not emit for an unchanged value of ${description}`, async () => { it(`does not emit for an unchanged value of ${description}`, async () => {
// arrange // arrange
const wrapper = mountComponent({ const wrapper = mountComponent({