@eturnity/eturnity_reusable_components 9.25.10 → 9.25.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/package.json +2 -3
- package/src/components/buttons/closeButton/closeButton.spec.js +34 -0
- package/src/components/buttons/splitButtons/index.vue +1 -1
- package/src/components/buttons/splitButtons/splitButtons.spec.js +40 -0
- package/src/components/errorMessage/errorMessage.spec.js +20 -20
- package/src/components/inputs/inputText/index.vue +17 -17
- package/src/components/projectMarker/index.vue +21 -26
package/README.md
CHANGED
|
@@ -212,3 +212,16 @@ Example:
|
|
|
212
212
|
```bash
|
|
213
213
|
npm run promote:provided-files-tag -- --version=9.15.2
|
|
214
214
|
```
|
|
215
|
+
|
|
216
|
+
## Testing
|
|
217
|
+
|
|
218
|
+
Unit tests are Jest + `@vue/test-utils`, co-located with each component as
|
|
219
|
+
`componentName.spec.js`. Run a single spec with `pnpm test <path>` or the full
|
|
220
|
+
suite with `pnpm test`. See [`docs/component-testing.md`](docs/component-testing.md)
|
|
221
|
+
for how we write tests (conventions, the TDD workflow, and using Claude Code).
|
|
222
|
+
|
|
223
|
+
## CI and pull requests
|
|
224
|
+
|
|
225
|
+
Opening or updating a pull request runs **Bitbucket Pipelines** ([`bitbucket-pipelines.yml`](bitbucket-pipelines.yml)): install with pnpm, **`pnpm test`**, then **`pnpm run build`**. PRs are expected to pass this pipeline.
|
|
226
|
+
|
|
227
|
+
**Blocking merges on failure** is configured in **Bitbucket repository settings** (not in this repo): enable merge checks that require a successful pull-request build—for example a minimum number of successful builds for the PR, or “require passing pipelines” if your plan supports it. Until that is enabled, a red pipeline is visible but may not stop merges automatically.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eturnity/eturnity_reusable_components",
|
|
3
|
-
"version": "9.25.
|
|
3
|
+
"version": "9.25.12",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist",
|
|
6
6
|
"src"
|
|
@@ -25,8 +25,7 @@
|
|
|
25
25
|
"test-coverage": "jest --coverage",
|
|
26
26
|
"merge-remote-master": "node scripts/merge-remote-master.js",
|
|
27
27
|
"prepack": "npm run verify:provided-files && npm run verify:provided-docs",
|
|
28
|
-
"
|
|
29
|
-
"prepublishOnly": "npm run maintain:components && npm run test && npm run build && npm run verify:provided-files && npm run verify:provided-docs"
|
|
28
|
+
"prepublishOnly": "npm run test && npm run build && npm run verify:provided-files && npm run verify:provided-docs"
|
|
30
29
|
},
|
|
31
30
|
"peerDependencies": {
|
|
32
31
|
"date-fns": "^3.0.0 || ^4.0.0",
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import CloseButton from '@/components/buttons/closeButton'
|
|
4
|
+
|
|
5
|
+
// Canonical example spec for the reusable component library.
|
|
6
|
+
// Reference for: mount, data-id / data-qa-id selectors, structural assertions.
|
|
7
|
+
// `theme` and `$gettext` are provided globally by jest.setup.js, so specs do
|
|
8
|
+
// not need to re-provide them.
|
|
9
|
+
|
|
10
|
+
describe('CloseButton', () => {
|
|
11
|
+
const mountButton = (props = {}) => mount(CloseButton, { props })
|
|
12
|
+
|
|
13
|
+
it('renders the two crossing lines inside the container', () => {
|
|
14
|
+
const container = mountButton({ dataId: 'close_btn' }).find(
|
|
15
|
+
'[data-id="close_btn"]'
|
|
16
|
+
)
|
|
17
|
+
expect(container.exists()).toBe(true)
|
|
18
|
+
expect(container.findAll('div')).toHaveLength(2)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('exposes dataId and dataQaId as data attributes', () => {
|
|
22
|
+
const wrapper = mountButton({ dataId: 'close_btn', dataQaId: 'qa_close' })
|
|
23
|
+
expect(wrapper.find('[data-id="close_btn"]').exists()).toBe(true)
|
|
24
|
+
expect(wrapper.find('[data-qa-id="qa_close"]').exists()).toBe(true)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('applies a generated style class to each line', () => {
|
|
28
|
+
const lines = mountButton({ dataId: 'close_btn' })
|
|
29
|
+
.find('[data-id="close_btn"]')
|
|
30
|
+
.findAll('div')
|
|
31
|
+
expect(lines).toHaveLength(2)
|
|
32
|
+
lines.forEach((line) => expect(line.classes().length).toBeGreaterThan(0))
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import SplitButtons from '@/components/buttons/splitButtons'
|
|
4
|
+
|
|
5
|
+
describe('SplitButtons', () => {
|
|
6
|
+
const options = [
|
|
7
|
+
{ label: 'Monthly', value: 'monthly' },
|
|
8
|
+
{ label: 'Yearly', value: 'yearly' },
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
const mountButtons = (props = {}) =>
|
|
12
|
+
mount(SplitButtons, {
|
|
13
|
+
props: { options, modelValue: 'monthly', dataIdKey: 'billing', ...props },
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('renders one button per option with its label', () => {
|
|
17
|
+
const buttons = mountButtons().findAll('button')
|
|
18
|
+
expect(buttons).toHaveLength(2)
|
|
19
|
+
expect(buttons[0].text()).toBe('Monthly')
|
|
20
|
+
expect(buttons[1].text()).toBe('Yearly')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('builds the data-id-key from the key and the option value', () => {
|
|
24
|
+
const wrapper = mountButtons()
|
|
25
|
+
expect(wrapper.find('[data-id-key="billing_monthly"]').exists()).toBe(true)
|
|
26
|
+
expect(wrapper.find('[data-id-key="billing_yearly"]').exists()).toBe(true)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('emits update:modelValue with the clicked option value', async () => {
|
|
30
|
+
const wrapper = mountButtons()
|
|
31
|
+
await wrapper.findAll('button')[1].trigger('click')
|
|
32
|
+
expect(wrapper.emitted('update:modelValue')).toEqual([['yearly']])
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('emits a declared click event with the clicked option value', async () => {
|
|
36
|
+
const wrapper = mountButtons()
|
|
37
|
+
await wrapper.findAll('button')[1].trigger('click')
|
|
38
|
+
expect(wrapper.emitted('click')).toEqual([['yearly']])
|
|
39
|
+
})
|
|
40
|
+
})
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
1
2
|
import { mount } from '@vue/test-utils'
|
|
2
3
|
import ErrorMessage from '@/components/errorMessage'
|
|
3
|
-
import theme from '@/assets/theme'
|
|
4
|
-
|
|
5
|
-
/* eslint-disable */
|
|
6
4
|
|
|
7
|
-
describe('ErrorMessage
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
wrapper = mount(ErrorMessage, {
|
|
12
|
-
props: {},
|
|
5
|
+
describe('ErrorMessage', () => {
|
|
6
|
+
const mountMessage = (props = {}) =>
|
|
7
|
+
mount(ErrorMessage, {
|
|
8
|
+
props,
|
|
13
9
|
slots: {
|
|
14
10
|
default: '<div data-test-id="fake-msg">testing</div>',
|
|
15
11
|
},
|
|
16
|
-
global: {
|
|
17
|
-
provide: {
|
|
18
|
-
theme,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
12
|
})
|
|
13
|
+
|
|
14
|
+
it('renders the default slot content', () => {
|
|
15
|
+
const wrapper = mountMessage()
|
|
16
|
+
const message = wrapper.find('[data-test-id="fake-msg"]')
|
|
17
|
+
expect(message.exists()).toBe(true)
|
|
18
|
+
expect(message.text()).toBe('testing')
|
|
22
19
|
})
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
it('uses the documented default props', () => {
|
|
22
|
+
const wrapper = mountMessage()
|
|
23
|
+
expect(wrapper.props('isRelative')).toBe(false)
|
|
24
|
+
expect(wrapper.props('marginTop')).toBe('13px')
|
|
26
25
|
})
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
it('renders different overlay styling for absolute (default) vs relative', () => {
|
|
28
|
+
const overlayClassOf = (props) =>
|
|
29
|
+
mountMessage(props).find('[data-test-id="fake-msg"]').element
|
|
30
|
+
.parentElement.className
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
expect(wrapper.props().marginTop).toBe('20px')
|
|
32
|
+
expect(overlayClassOf()).not.toBe(overlayClassOf({ isRelative: true }))
|
|
33
33
|
})
|
|
34
34
|
})
|
|
@@ -125,8 +125,8 @@
|
|
|
125
125
|
props.theme.colors[props.labelFontColor]
|
|
126
126
|
? props.theme.colors[props.labelFontColor]
|
|
127
127
|
: props.labelFontColor
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
? props.labelFontColor
|
|
129
|
+
: props.theme.colors.eturnityGrey};
|
|
130
130
|
|
|
131
131
|
font-size: ${(props) =>
|
|
132
132
|
props.fontSize ? props.fontSize : inputLabelFontSize};
|
|
@@ -172,29 +172,29 @@
|
|
|
172
172
|
props.noBorder
|
|
173
173
|
? 'none'
|
|
174
174
|
: props.isError
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
175
|
+
? '1px solid ' + props.theme.colors.red
|
|
176
|
+
: props.borderColor
|
|
177
|
+
? props.theme.colors[props.borderColor]
|
|
178
|
+
? '1px solid ' + props.theme.colors[props.borderColor]
|
|
179
|
+
: '1px solid ' + props.borderColor
|
|
180
|
+
: '1px solid ' + props.theme.colors.grey4};
|
|
181
181
|
padding: ${(props) =>
|
|
182
182
|
props.isError
|
|
183
183
|
? '11px 25px 11px 10px'
|
|
184
184
|
: props.inputType === 'password'
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
? '11px 25px 11px 10px'
|
|
186
|
+
: props.defaultPadding
|
|
187
|
+
? '10px 35px 10px 15px'
|
|
188
|
+
: '11px 5px 11px 10px'};
|
|
189
189
|
border-radius: 4px;
|
|
190
190
|
position: relative;
|
|
191
|
-
font-size: ${(props) => (props.fontSize ? props.fontSize : '
|
|
191
|
+
font-size: ${(props) => (props.fontSize ? props.fontSize : '13px')};
|
|
192
192
|
color: ${(props) =>
|
|
193
193
|
props.isDisabled
|
|
194
194
|
? props.theme.colors.grey2
|
|
195
195
|
: props.fontColor
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
? props.fontColor + ' !important'
|
|
197
|
+
: props.theme.semanticColors.grey[900]};
|
|
198
198
|
|
|
199
199
|
width: ${(props) => (props.inputWidth ? props.inputWidth : '100%')};
|
|
200
200
|
min-width: ${(props) => (props.minWidth ? props.minWidth : 'unset')};
|
|
@@ -208,8 +208,8 @@
|
|
|
208
208
|
? props.disabledBackgroundColor + ' !important'
|
|
209
209
|
: props.theme.colors.grey5
|
|
210
210
|
: props.backgroundColor
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
? props.backgroundColor + ' !important'
|
|
212
|
+
: props.theme.colors.white};
|
|
213
213
|
&::placeholder {
|
|
214
214
|
color: ${(props) => props.theme.colors.grey2};
|
|
215
215
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
<PillWrapper
|
|
4
4
|
v-if="markerData && markerData.translations[activeLanguage]"
|
|
5
5
|
:cursor="editionAllowed ? 'pointer' : cursor"
|
|
6
|
-
:with-date="!!date"
|
|
7
6
|
:truncate-label="truncateLabel"
|
|
7
|
+
:with-date="!!date"
|
|
8
8
|
@click="editionAllowed ? (activated = !activated) : null"
|
|
9
9
|
>
|
|
10
10
|
<PillContent :truncate-label="truncateLabel">
|
|
@@ -58,19 +58,23 @@
|
|
|
58
58
|
:prevent-outside-close="true"
|
|
59
59
|
@on-close="closeDeleteModal"
|
|
60
60
|
>
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
<ModalContent>
|
|
62
|
+
<ModalTitle>
|
|
63
|
+
{{ $gettext('delete_confirm_text') }}
|
|
64
|
+
</ModalTitle>
|
|
65
|
+
<ModalBody>
|
|
66
|
+
{{ $gettext('delete_confirm_subtext') }}
|
|
67
|
+
</ModalBody>
|
|
68
|
+
<ModalButtonContainer>
|
|
66
69
|
<MainButton
|
|
67
70
|
:text="$gettext('Cancel')"
|
|
68
|
-
type="
|
|
71
|
+
type="tertiary"
|
|
69
72
|
variant="cancel"
|
|
70
73
|
@click="closeDeleteModal"
|
|
71
74
|
/>
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
<MainButton :text="$gettext('Delete')" @click="onDelete" />
|
|
76
|
+
</ModalButtonContainer>
|
|
77
|
+
</ModalContent>
|
|
74
78
|
</Modal>
|
|
75
79
|
</PageContainer>
|
|
76
80
|
</template>
|
|
@@ -94,9 +98,11 @@
|
|
|
94
98
|
import vClickOutside from 'click-outside-vue3'
|
|
95
99
|
import Icon from '../icon'
|
|
96
100
|
import Modal from '../modals/modal'
|
|
97
|
-
import
|
|
101
|
+
import ModalContent from '../modals/modalContent'
|
|
102
|
+
import ModalTitle from '../modals/modalTitle'
|
|
103
|
+
import ModalBody from '../modals/modalBody'
|
|
104
|
+
import ModalButtonContainer from '../modals/modalButtonContainer'
|
|
98
105
|
import DeleteIcon from '../deleteIcon'
|
|
99
|
-
import PageSubtitle from '../pageSubtitle'
|
|
100
106
|
import MainButton from '../buttons/mainButton'
|
|
101
107
|
|
|
102
108
|
const PageContainerProps = { truncateLabel: Boolean }
|
|
@@ -113,17 +119,6 @@
|
|
|
113
119
|
`}
|
|
114
120
|
`
|
|
115
121
|
|
|
116
|
-
const ModalContainer = styled.div`
|
|
117
|
-
padding: 40px;
|
|
118
|
-
min-width: 500px;
|
|
119
|
-
`
|
|
120
|
-
|
|
121
|
-
const CtaContainer = styled.div`
|
|
122
|
-
display: flex;
|
|
123
|
-
gap: 20px;
|
|
124
|
-
margin-top: 30px;
|
|
125
|
-
`
|
|
126
|
-
|
|
127
122
|
const PillWrapperProps = {
|
|
128
123
|
withDate: Boolean,
|
|
129
124
|
cursor: String,
|
|
@@ -281,10 +276,10 @@
|
|
|
281
276
|
IconContainer,
|
|
282
277
|
Icon,
|
|
283
278
|
Modal,
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
279
|
+
ModalButtonContainer,
|
|
280
|
+
ModalTitle,
|
|
281
|
+
ModalBody,
|
|
282
|
+
ModalContent,
|
|
288
283
|
MainButton,
|
|
289
284
|
PillDate,
|
|
290
285
|
MarkerName,
|