diff --git a/src/app/components/Form/QuotaField.vue b/src/app/components/Form/QuotaField.vue new file mode 100644 index 00000000..4331839f --- /dev/null +++ b/src/app/components/Form/QuotaField.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/app/pages/clients/[id].vue b/src/app/pages/clients/[id].vue index 6694c284..fa63ed59 100644 --- a/src/app/pages/clients/[id].vue +++ b/src/app/pages/clients/[id].vue @@ -29,6 +29,26 @@ :label="$t('client.expireDate')" /> + + + {{ $t('client.trafficQuotas') }} + + + + + {{ $t('client.address') }} { + test('keeps disabled quotas null', () => { + expect(quotaBytesToGiB(null)).toBeNull(); + expect(quotaGiBToBytes(null)).toBeNull(); + expect(quotaGiBToBytes(0)).toBeNull(); + }); + + test('converts whole and fractional GiB to bytes', () => { + expect(quotaGiBToBytes(1)).toBe(GIBIBYTE_IN_BYTES); + expect(quotaGiBToBytes(0.5)).toBe(GIBIBYTE_IN_BYTES / 2); + expect(quotaGiBToBytes(1 / GIBIBYTE_IN_BYTES)).toBe(1); + }); + + test('rounds edited GiB values to the nearest byte', () => { + expect(quotaGiBToBytes(1.5 / GIBIBYTE_IN_BYTES)).toBe(2); + }); + + test.each([1, 150, GIBIBYTE_IN_BYTES, Number.MAX_SAFE_INTEGER])( + 'round-trips the exact byte value %s', + (bytes) => { + expect(quotaGiBToBytes(quotaBytesToGiB(bytes))).toBe(bytes); + } + ); +}); diff --git a/src/vitest.config.ts b/src/vitest.config.ts index 2c56bf49..45ca83e4 100644 --- a/src/vitest.config.ts +++ b/src/vitest.config.ts @@ -10,6 +10,7 @@ export default defineConfig({ alias: { '#server': fileURLToPath(new URL('./server', import.meta.url)), '#shared': fileURLToPath(new URL('./shared', import.meta.url)), + '#app': fileURLToPath(new URL('./app', import.meta.url)), }, }, test: {