Fix json serialization (#16558)

* fix copying json fields

* fixed preset filter type

* handling fallback in copyToClipboard function

* add test

* try parsing json content on paste

Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com>
This commit is contained in:
Brainslug
2022-12-15 10:40:43 +01:00
committed by GitHub
parent bbcf76e030
commit 511c8d368b
4 changed files with 135 additions and 5 deletions

View File

@@ -81,6 +81,7 @@ import FormFieldMenu from './form-field-menu.vue';
import { formatFieldFunction } from '@/utils/format-field-function';
import { useClipboard } from '@/composables/use-clipboard';
import FormFieldRawEditor from './form-field-raw-editor.vue';
import { parseJSON } from '@directus/shared/utils';
interface Props {
field: Field;
@@ -178,8 +179,12 @@ function useRaw() {
async function pasteRaw() {
const pastedValue = await pasteFromClipboard();
if (!pastedValue) return;
internalValue.value = pastedValue;
emitValue(pastedValue);
try {
internalValue.value = parseJSON(pastedValue);
} catch (e) {
internalValue.value = pastedValue;
}
emitValue(internalValue.value);
}
return { showRaw, copyRaw, pasteRaw, onRawValueSubmit };

View File

@@ -0,0 +1,124 @@
import { mount } from '@vue/test-utils';
import { GlobalMountOptions } from '@vue/test-utils/dist/types';
import { afterEach, beforeAll, describe, expect, test, vi } from 'vitest';
import { defineComponent, h, unref } from 'vue';
import { createI18n } from 'vue-i18n';
import { useClipboard } from './use-clipboard';
vi.mock('@/utils/notify', () => ({
notify: vi.fn(),
}));
const i18n = createI18n({ legacy: false });
const global: GlobalMountOptions = {
plugins: [i18n],
};
const testComponent = defineComponent({
setup() {
return useClipboard();
},
render: () => h('div'),
});
describe('useClipboard', () => {
beforeAll(() => {
vi.spyOn(i18n.global, 't').mockImplementation((key) => key as any);
});
afterEach(() => {
vi.resetAllMocks();
});
test.each([
{ value: { writeText: vi.fn() }, expectedResult: true },
{ value: {}, expectedResult: false },
])('isCopySupported should be $expectedResult', ({ value, expectedResult }) => {
Object.defineProperty(navigator, 'clipboard', { value, configurable: true });
const wrapper = mount(testComponent, { global });
expect(unref(wrapper.vm.isCopySupported)).toBe(expectedResult);
});
test.each([
{ value: { readText: vi.fn() }, expectedResult: true },
{ value: {}, expectedResult: false },
])('isPasteSupported should be $expectedResult', ({ value, expectedResult }) => {
Object.defineProperty(navigator, 'clipboard', { value, configurable: true });
const wrapper = mount(testComponent, { global });
expect(unref(wrapper.vm.isPasteSupported)).toBe(expectedResult);
});
test('copyToClipboard with string value returns true', async () => {
Object.defineProperty(navigator, 'clipboard', { value: { writeText: vi.fn() }, configurable: true });
const writeTextSpy = vi.spyOn(navigator.clipboard, 'writeText');
const copyValue = 'test';
const wrapper = mount(testComponent, { global });
const isCopied = await wrapper.vm.copyToClipboard(copyValue);
expect(writeTextSpy).toHaveBeenCalledWith(copyValue);
expect(isCopied).toBe(true);
});
test('copyToClipboard with json value stringifies it and returns true', async () => {
Object.defineProperty(navigator, 'clipboard', { value: { writeText: vi.fn() }, configurable: true });
const writeTextSpy = vi.spyOn(navigator.clipboard, 'writeText');
const copyValue = { test: 'value' };
const wrapper = mount(testComponent, { global });
const isCopied = await wrapper.vm.copyToClipboard(copyValue);
expect(writeTextSpy).toHaveBeenCalledWith(JSON.stringify(copyValue));
expect(isCopied).toBe(true);
});
test('copyToClipboard returns false when it fails', async () => {
Object.defineProperty(navigator, 'clipboard', {
value: { writeText: vi.fn().mockImplementation(() => Promise.reject()) },
configurable: true,
});
const copyValue = 'test';
const wrapper = mount(testComponent, { global });
const isCopied = await wrapper.vm.copyToClipboard(copyValue);
expect(isCopied).toBe(false);
});
test('pasteFromClipboard returns string when it succeeds', async () => {
const testClipboardValue = 'test';
Object.defineProperty(navigator, 'clipboard', {
value: { readText: vi.fn().mockReturnValue(testClipboardValue) },
configurable: true,
});
const wrapper = mount(testComponent, { global });
const clipboardValue = await wrapper.vm.pasteFromClipboard();
expect(clipboardValue).toBe(testClipboardValue);
});
test('pasteFromClipboard returns null when it fails', async () => {
Object.defineProperty(navigator, 'clipboard', {
value: { readText: vi.fn().mockImplementation(() => Promise.reject()) },
configurable: true,
});
const wrapper = mount(testComponent, { global });
const clipboardValue = await wrapper.vm.pasteFromClipboard();
expect(clipboardValue).toBe(null);
});
});

View File

@@ -20,9 +20,10 @@ export function useClipboard() {
return { isCopySupported, isPasteSupported, copyToClipboard, pasteFromClipboard };
async function copyToClipboard(value: string, message?: Message): Promise<boolean> {
async function copyToClipboard(value: any, message?: Message): Promise<boolean> {
try {
await navigator?.clipboard?.writeText(value);
const valueString = typeof value === 'string' ? value : JSON.stringify(value);
await navigator?.clipboard?.writeText(valueString);
notify({
title: message?.success ?? t('copy_raw_value_success'),
});

View File

@@ -528,7 +528,7 @@ function useForm() {
{
field: 'filter',
name: t('filter'),
type: 'string',
type: 'json',
meta: {
interface: 'system-filter',
width: 'half',