diff --git a/jestHelpers/setup.js b/jestHelpers/setup.js index a8e20229ad..434aecf3d0 100644 --- a/jestHelpers/setup.js +++ b/jestHelpers/setup.js @@ -2,6 +2,27 @@ import React from 'react' global.cozy = {} +global.fetch = jest.fn(() => + Promise.resolve({ + ok: true, + status: 200, + headers: { + get: jest.fn(name => { + if (name.toLowerCase() === 'content-type') { + return 'application/json' + } + return null + }) + }, + json: async () => ({ + rows: [], + data: [] + }), + text: async () => '', + blob: async () => new Blob() + }) +) + jest.mock('cozy-bar', () => ({ ...jest.requireActual('cozy-bar'), BarComponent: () =>
Bar
, diff --git a/src/components/FolderPicker/FolderPickerHeader.spec.js b/src/components/FolderPicker/FolderPickerHeader.spec.js index 92a58717dd..3eb66f7e19 100644 --- a/src/components/FolderPicker/FolderPickerHeader.spec.js +++ b/src/components/FolderPicker/FolderPickerHeader.spec.js @@ -1,4 +1,4 @@ -import { render } from '@testing-library/react' +import { render, act } from '@testing-library/react' import React from 'react' import CozyClient from 'cozy-client' @@ -11,7 +11,7 @@ jest.mock('lib/logger', () => ({ })) describe('FolderPickerHeader', () => { - const setupComponent = ({ entries = [], title, subTitle }) => { + const setupComponent = async ({ entries = [], title, subTitle }) => { const props = { entries, @@ -20,26 +20,30 @@ describe('FolderPickerHeader', () => { } const client = new CozyClient({}) - return render( - - - - ) + let component + await act(async () => { + component = render( + + + + ) + }) + return component } - it('should fallback to Move title if no title is given', () => { - const { getByText } = setupComponent({ + it('should fallback to Move title if no title is given', async () => { + const { getByText } = await setupComponent({ entries: [{ file: 1 }, { file: 2 }] }) expect(getByText('2 elements')) }) - it('should display title if title is given and no file', () => { - const { getByText } = setupComponent({ + it('should display title if title is given and no file', async () => { + const { getByText } = await setupComponent({ title: 'My Title' }) expect(getByText('My Title')) }) - it('should display the right title if only one io.cozy.files', () => { - const { getByText } = setupComponent({ + it('should display the right title if only one io.cozy.files', async () => { + const { getByText } = await setupComponent({ title: 'My Title', entries: [ { @@ -51,8 +55,8 @@ describe('FolderPickerHeader', () => { expect(getByText('FileName.txt')) }) - it('should display the right title if it comes from the outside', () => { - const { getByText } = setupComponent({ + it('should display the right title if it comes from the outside', async () => { + const { getByText } = await setupComponent({ title: 'My Title', entries: [ { @@ -62,8 +66,8 @@ describe('FolderPickerHeader', () => { }) expect(getByText('FileName.txt')) }) - it('should display the right title if more than one files', () => { - const { getByText } = setupComponent({ + it('should display the right title if more than one files', async () => { + const { getByText } = await setupComponent({ title: 'My Title', entries: [ { diff --git a/src/hooks/useFolderSort/index.spec.jsx b/src/hooks/useFolderSort/index.spec.jsx index cbdef0811e..b6f0d77bce 100644 --- a/src/hooks/useFolderSort/index.spec.jsx +++ b/src/hooks/useFolderSort/index.spec.jsx @@ -1,24 +1,29 @@ import { renderHook, act } from '@testing-library/react-hooks' -import { useClient } from 'cozy-client' +import { useClient, useQuery } from 'cozy-client' import flag from 'cozy-flags' import { useFolderSort } from './index' import { DEFAULT_SORT, SORT_BY_UPDATE_DATE } from '@/config/sort' import { TRASH_DIR_ID } from '@/constants/config' -import { DOCTYPE_DRIVE_SETTINGS } from '@/lib/doctypes' import logger from '@/lib/logger' import { usePublicContext } from '@/modules/public/PublicProvider' jest.mock('cozy-client', () => ({ useClient: jest.fn(), - Q: jest.fn().mockReturnValue('mocked-query'), useQuery: jest.fn() })) jest.mock('cozy-flags', () => jest.fn()) +jest.mock('@/queries', () => ({ + getDriveSettingQuery: { + definition: jest.fn(), + options: { as: 'io.cozy.drive.settings' } + } +})) + jest.mock('@/lib/logger', () => ({ warn: jest.fn(), info: jest.fn(), @@ -30,6 +35,7 @@ jest.mock('@/modules/public/PublicProvider', () => ({ })) const mockUseClient = useClient +const mockUseQuery = useQuery const mockFlag = flag const mockUsePublicContext = usePublicContext @@ -43,10 +49,10 @@ describe('useFolderSort', () => { consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}) mockClient = { - save: jest.fn().mockResolvedValue({}), - query: jest.fn().mockResolvedValue({ data: [] }) + save: jest.fn().mockResolvedValue({}) } mockUseClient.mockReturnValue(mockClient) + mockUseQuery.mockReturnValue({ data: [] }) mockFlag.mockImplementation(flagName => { if (flagName === 'drive.save-sort-choice.enabled') { @@ -67,9 +73,7 @@ describe('useFolderSort', () => { describe('default sort behavior', () => { it('should use DEFAULT_SORT for regular folders', () => { const folderId = 'regular-folder-id' - mockClient.query.mockResolvedValue({ - data: [] - }) + mockUseQuery.mockReturnValue({ data: [] }) const { result } = renderHook(() => useFolderSort(folderId)) @@ -79,9 +83,7 @@ describe('useFolderSort', () => { it('should use SORT_BY_UPDATE_DATE for trash folder', () => { const folderId = TRASH_DIR_ID - mockClient.query.mockResolvedValue({ - data: [] - }) + mockUseQuery.mockReturnValue({ data: [] }) const { result } = renderHook(() => useFolderSort(folderId)) @@ -91,9 +93,7 @@ describe('useFolderSort', () => { it('should use SORT_BY_UPDATE_DATE for recent folder', () => { const folderId = 'recent' - mockClient.query.mockResolvedValue({ - data: [] - }) + mockUseQuery.mockReturnValue({ data: [] }) const { result } = renderHook(() => useFolderSort(folderId)) @@ -103,26 +103,22 @@ describe('useFolderSort', () => { }) describe('loading existing sorting settings', () => { - it('should load and apply existing sorting settings when available', async () => { + it('should load and apply existing sorting settings when available', () => { const folderId = 'test-folder' const existingSettings = { _id: 'settings-id', - _type: DOCTYPE_DRIVE_SETTINGS, + _type: 'io.cozy.drive.settings', attributes: { attribute: 'updated_at', order: 'desc' } } - mockClient.query.mockResolvedValue({ + mockUseQuery.mockReturnValue({ data: [existingSettings] }) - const { result, waitForNextUpdate } = renderHook(() => - useFolderSort(folderId) - ) - - await waitForNextUpdate() + const { result } = renderHook(() => useFolderSort(folderId)) const [currentSort] = result.current expect(currentSort).toEqual({ @@ -135,10 +131,10 @@ describe('useFolderSort', () => { const folderId = 'test-folder' const existingSettings = { _id: 'settings-id', - _type: DOCTYPE_DRIVE_SETTINGS + _type: 'io.cozy.drive.settings' } - mockClient.query.mockResolvedValue({ + mockUseQuery.mockReturnValue({ data: [existingSettings] }) @@ -148,26 +144,22 @@ describe('useFolderSort', () => { expect(currentSort).toEqual(DEFAULT_SORT) }) - it('should return consistent sort values on multiple renders', async () => { + it('should return consistent sort values on multiple renders', () => { const folderId = 'test-folder' const existingSettings = { _id: 'settings-id', - _type: DOCTYPE_DRIVE_SETTINGS, + _type: 'io.cozy.drive.settings', attributes: { attribute: 'name', order: 'asc' } } - mockClient.query.mockResolvedValue({ + mockUseQuery.mockReturnValue({ data: [existingSettings] }) - const { result, rerender, waitForNextUpdate } = renderHook(() => - useFolderSort(folderId) - ) - - await waitForNextUpdate() + const { result, rerender } = renderHook(() => useFolderSort(folderId)) const [firstSort] = result.current expect(firstSort).toEqual({ @@ -190,9 +182,7 @@ describe('useFolderSort', () => { const folderId = 'test-folder' const newSort = { attribute: 'updated_at', order: 'desc' } - mockClient.query.mockResolvedValue({ - data: [] - }) + mockUseQuery.mockReturnValue({ data: [] }) const { result } = renderHook(() => useFolderSort(folderId)) @@ -202,9 +192,8 @@ describe('useFolderSort', () => { }) expect(mockClient.save).toHaveBeenCalledWith({ - _type: DOCTYPE_DRIVE_SETTINGS, + _type: 'io.cozy.drive.settings', attributes: { - ...DEFAULT_SORT, attribute: 'updated_at', order: 'desc' } @@ -220,7 +209,7 @@ describe('useFolderSort', () => { const folderId = 'test-folder' const existingSettings = { _id: 'settings-id', - _type: DOCTYPE_DRIVE_SETTINGS, + _type: 'io.cozy.drive.settings', attributes: { attribute: 'name', order: 'asc' @@ -228,16 +217,11 @@ describe('useFolderSort', () => { } const newSort = { attribute: 'updated_at', order: 'desc' } - mockClient.query.mockResolvedValue({ + mockUseQuery.mockReturnValue({ data: [existingSettings] }) - const { result, waitForNextUpdate } = renderHook(() => - useFolderSort(folderId) - ) - - // Wait for the settings to load - await waitForNextUpdate() + const { result } = renderHook(() => useFolderSort(folderId)) const [, setSortOrder] = result.current await act(async () => { @@ -258,15 +242,47 @@ describe('useFolderSort', () => { ) }) + it('should preserve other attributes when updating sorting settings', async () => { + const folderId = 'test-folder' + const existingSettings = { + _id: 'settings-id', + _type: 'io.cozy.drive.settings', + attributes: { + attribute: 'name', + order: 'asc', + preferredDriveViewType: 'grid' + } + } + const newSort = { attribute: 'updated_at', order: 'desc' } + + mockUseQuery.mockReturnValue({ + data: [existingSettings] + }) + + const { result } = renderHook(() => useFolderSort(folderId)) + + const [, setSortOrder] = result.current + await act(async () => { + await setSortOrder(newSort) + }) + + expect(mockClient.save).toHaveBeenCalledWith({ + ...existingSettings, + attributes: { + attribute: 'updated_at', + order: 'desc', + preferredDriveViewType: 'grid' + } + }) + }) + it('should handle save errors gracefully', async () => { const folderId = 'test-folder' const newSort = { attribute: 'updated_at', order: 'desc' } const saveError = new Error('Save failed') mockClient.save.mockRejectedValue(saveError) - mockClient.query.mockResolvedValue({ - data: [] - }) + mockUseQuery.mockReturnValue({ data: [] }) const { result } = renderHook(() => useFolderSort(folderId)) @@ -283,11 +299,11 @@ describe('useFolderSort', () => { }) describe('public context behavior', () => { - it('should not load settings in public view', async () => { + it('should not load settings in public view', () => { const folderId = 'test-folder' const existingSettings = { _id: 'settings-id', - _type: DOCTYPE_DRIVE_SETTINGS, + _type: 'io.cozy.drive.settings', attributes: { attribute: 'updated_at', order: 'desc' @@ -298,7 +314,7 @@ describe('useFolderSort', () => { isPublic: true }) - mockClient.query.mockResolvedValue({ + mockUseQuery.mockReturnValue({ data: [existingSettings] }) @@ -307,8 +323,6 @@ describe('useFolderSort', () => { const [currentSort] = result.current expect(currentSort).toEqual(DEFAULT_SORT) - - expect(mockClient.query).not.toHaveBeenCalled() }) it('should not persist settings in public view', async () => { @@ -331,8 +345,6 @@ describe('useFolderSort', () => { ) expect(mockClient.save).not.toHaveBeenCalled() - - expect(mockClient.query).not.toHaveBeenCalled() }) }) }) diff --git a/src/hooks/useFolderSort/index.ts b/src/hooks/useFolderSort/index.ts index b2e95cc591..277c249bbd 100644 --- a/src/hooks/useFolderSort/index.ts +++ b/src/hooks/useFolderSort/index.ts @@ -1,12 +1,12 @@ import { useCallback, useEffect, useState } from 'react' -import { useClient, Q } from 'cozy-client' +import { useClient, useQuery } from 'cozy-client' import flag from 'cozy-flags' import { DEFAULT_SORT, SORT_BY_UPDATE_DATE } from '@/config/sort' import { RECENT_FOLDER_ID, TRASH_DIR_ID } from '@/constants/config' -import { DOCTYPE_DRIVE_SETTINGS } from '@/lib/doctypes' import logger from '@/lib/logger' +import { getDriveSettingQuery } from '@/queries' import { usePublicContext } from '@/modules/public/PublicProvider' export interface Sort { @@ -19,11 +19,6 @@ interface DriveSettings { attributes: Sort } -interface QueryResult { - data?: DriveSettings[] - fetchStatus?: string -} - const useFolderSort = ( folderId: string ): [Sort, (props: Sort) => void, boolean] => { @@ -38,30 +33,22 @@ const useFolderSort = ( const [currentSort, setCurrentSort] = useState(defaultSort) const [isSaving, setIsSaving] = useState(false) - useEffect(() => { - const load = async (): Promise => { - if (!client || !flag('drive.save-sort-choice.enabled') || isPublic) { - setIsSettingsLoaded(true) - return - } + const settingsQuery = useQuery(getDriveSettingQuery.definition, { + ...getDriveSettingQuery.options, + enabled: flag('drive.save-sort-choice.enabled') + }) as { + data?: DriveSettings[] + } - try { - const { data } = (await client.query( - Q(DOCTYPE_DRIVE_SETTINGS) - )) as QueryResult - - if (!data?.length) return + useEffect(() => { + if (!flag('drive.save-sort-choice.enabled') || isPublic) return - setCurrentSort(data[0]?.attributes) - } catch (error) { - logger.error('Failed to load settings:', error) - } finally { - setIsSettingsLoaded(true) - } + if (settingsQuery.data?.length && settingsQuery.data[0]?.attributes) { + setCurrentSort(settingsQuery.data[0].attributes) } - void load() - }, [client, isPublic]) + setIsSettingsLoaded(true) + }, [isPublic, settingsQuery.data]) const setSortOrder = useCallback( async ({ attribute, order }: Sort) => { @@ -90,19 +77,15 @@ const useFolderSort = ( setIsSaving(true) try { - const { data } = (await client.query( - Q(DOCTYPE_DRIVE_SETTINGS) - )) as QueryResult - - const settingsToSave: DriveSettings = data?.length - ? { - ...data[0], - attributes: { attribute, order } - } - : { - _type: DOCTYPE_DRIVE_SETTINGS, - attributes: { attribute, order } - } + const existing = settingsQuery.data?.[0] + const settingsToSave = { + ...(existing || { _type: 'io.cozy.drive.settings' }), + attributes: { + ...(existing?.attributes || {}), + attribute, + order + } + } await client.save(settingsToSave) logger.info('Sort settings persisted', { attribute, order }) @@ -112,7 +95,7 @@ const useFolderSort = ( setIsSaving(false) } }, - [client, isSaving, isPublic, setIsSaving] + [client, isSaving, setIsSaving, isPublic, settingsQuery.data] ) return [currentSort, setSortOrder, isSettingsLoaded] diff --git a/src/lib/ViewSwitcherContext.tsx b/src/lib/ViewSwitcherContext.tsx index fae847ea07..2d08b9deba 100644 --- a/src/lib/ViewSwitcherContext.tsx +++ b/src/lib/ViewSwitcherContext.tsx @@ -1,10 +1,10 @@ import React, { useState, useContext, createContext, useEffect } from 'react' -import { useClient, Q } from 'cozy-client' +import { useClient, useQuery } from 'cozy-client' import logger from './logger' - -import { DOCTYPE_FILES_SETTINGS } from '@/lib/doctypes' +import { getDriveSettingQuery } from '@/queries' +import { DOCTYPE_DRIVE_SETTINGS } from '@/lib/doctypes' interface QueryResult { data: [ @@ -31,53 +31,31 @@ const ViewSwitcherContext = createContext({ const ViewSwitcherContextProvider: React.FC = ({ children }) => { const client = useClient() const [viewType, setViewType] = useState(DEFAULT_VIEW_TYPE) + const settingsQuery = useQuery( + getDriveSettingQuery.definition, + getDriveSettingQuery.options + ) as QueryResult useEffect(() => { - const load = async (): Promise => { - if (!client) return - - try { - const result = (await client.query( - Q(DOCTYPE_FILES_SETTINGS) - )) as QueryResult - - if (!result?.data) return - - const preferred = result?.data?.[0]?.attributes?.preferredDriveViewType - - setViewType(preferred || DEFAULT_VIEW_TYPE) - } catch (error) { - logger.error('Failed to load settings:', error) - setViewType(DEFAULT_VIEW_TYPE) - } + if (settingsQuery.data?.length) { + const preferred = + settingsQuery.data[0]?.attributes?.preferredDriveViewType + setViewType(preferred || DEFAULT_VIEW_TYPE) } - - void load() - }, [client]) + }, [settingsQuery.data]) const switchView = async (viewTypeParam: string): Promise => { setViewType(viewTypeParam) if (!client) { logger.warn('Client not available') - return } try { - const { data } = (await client.query( - Q(DOCTYPE_FILES_SETTINGS) - )) as QueryResult - - if (!data) { - logger.warn('Settings not found') - - return - } - - const existing = data?.[0] + const existing = settingsQuery.data?.[0] await client.save({ - ...(existing || { _type: DOCTYPE_FILES_SETTINGS }), + ...(existing || { _type: DOCTYPE_DRIVE_SETTINGS }), attributes: { ...(existing?.attributes || {}), preferredDriveViewType: viewTypeParam diff --git a/src/modules/drive/RenameInput.spec.jsx b/src/modules/drive/RenameInput.spec.jsx index 264bdb6381..ffe0621acc 100644 --- a/src/modules/drive/RenameInput.spec.jsx +++ b/src/modules/drive/RenameInput.spec.jsx @@ -18,6 +18,14 @@ jest.mock('cozy-ui/transpiled/react/providers/Alert', () => ({ useAlert: jest.fn() })) +jest.mock('@/lib/ViewSwitcherContext', () => ({ + ViewSwitcherContextProvider: ({ children }) => children, + useViewSwitcherContext: jest.fn(() => ({ + viewType: 'list', + switchView: jest.fn() + })) +})) + describe('RenameInput', () => { let client let onAbort diff --git a/src/modules/drive/Toolbar/delete/DeleteItem.spec.jsx b/src/modules/drive/Toolbar/delete/DeleteItem.spec.jsx index e5b2f1e88a..95c8b0c844 100644 --- a/src/modules/drive/Toolbar/delete/DeleteItem.spec.jsx +++ b/src/modules/drive/Toolbar/delete/DeleteItem.spec.jsx @@ -1,4 +1,4 @@ -import { render, fireEvent } from '@testing-library/react' +import { render, fireEvent, act } from '@testing-library/react' import React from 'react' import DeleteItem from './DeleteItem' @@ -15,7 +15,7 @@ jest.mock('lib/logger', () => ({ })) describe('DeleteItem', () => { - const setup = () => { + const setup = async () => { const displayedFolder = { _id: 'displayed-folder-id', name: 'My Folder' @@ -24,20 +24,23 @@ describe('DeleteItem', () => { jest.spyOn(store, 'dispatch') const onLeave = jest.fn() - const container = render( - - - - ) + let container + await act(async () => { + container = render( + + + + ) + }) return { container, store, displayedFolder } } it('should show a modal', async () => { - const { container, store, displayedFolder } = setup() + const { container, store, displayedFolder } = await setup() const confirmButton = container.getByText('Remove') fireEvent.click(confirmButton) expect(store.dispatch).toHaveBeenCalledWith( diff --git a/src/modules/drive/Toolbar/delete/delete.spec.jsx b/src/modules/drive/Toolbar/delete/delete.spec.jsx index 0355538b93..caa43bfe80 100644 --- a/src/modules/drive/Toolbar/delete/delete.spec.jsx +++ b/src/modules/drive/Toolbar/delete/delete.spec.jsx @@ -16,6 +16,14 @@ jest.mock('react-router-dom', () => ({ useNavigate: () => mockNavigate })) +jest.mock('@/lib/ViewSwitcherContext', () => ({ + ViewSwitcherContextProvider: ({ children }) => children, + useViewSwitcherContext: jest.fn(() => ({ + viewType: 'list', + switchView: jest.fn() + })) +})) + describe('EnhancedDeleteConfirm', () => { const setup = () => { const folder = { diff --git a/src/modules/filelist/AddFolder.spec.jsx b/src/modules/filelist/AddFolder.spec.jsx index e94b154d9e..a3c47bc9e7 100644 --- a/src/modules/filelist/AddFolder.spec.jsx +++ b/src/modules/filelist/AddFolder.spec.jsx @@ -20,6 +20,14 @@ jest.mock('cozy-keys-lib', () => ({ WebVaultClient: jest.fn().mockReturnValue({}) })) +jest.mock('@/lib/ViewSwitcherContext', () => ({ + ViewSwitcherContextProvider: ({ children }) => children, + useViewSwitcherContext: jest.fn(() => ({ + viewType: 'list', + switchView: jest.fn() + })) +})) + describe('AddFolder', () => { const setup = () => { const { client, store } = setupStoreAndClient({}) diff --git a/src/modules/viewer/FilesViewer.spec.jsx b/src/modules/viewer/FilesViewer.spec.jsx index f270f1b6cb..b1e3c6d864 100644 --- a/src/modules/viewer/FilesViewer.spec.jsx +++ b/src/modules/viewer/FilesViewer.spec.jsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react' +import { render, screen, act } from '@testing-library/react' import React from 'react' import CozyClient, { useQuery } from 'cozy-client' @@ -33,6 +33,14 @@ jest.mock('cozy-viewer', () => ({ default: () =>
Viewer
})) +jest.mock('@/lib/ViewSwitcherContext', () => ({ + ViewSwitcherContextProvider: ({ children }) => children, + useViewSwitcherContext: jest.fn(() => ({ + viewType: 'list', + switchView: jest.fn() + })) +})) + const sleep = duration => new Promise(resolve => setTimeout(resolve, duration)) describe('FilesViewer', () => { @@ -115,15 +123,17 @@ describe('FilesViewer', () => { const hasMore = jest.fn().mockReturnValue(true) - setup({ - client, - nbFiles: 50, - totalCount: 100, - fileId: 'file-foobar48', - useQueryResultAttributes: { - fetchMore, - hasMore - } + await act(async () => { + setup({ + client, + nbFiles: 50, + totalCount: 100, + fileId: 'file-foobar48', + useQueryResultAttributes: { + fetchMore, + hasMore + } + }) }) const viewer = await screen.findByText('Viewer') diff --git a/src/modules/views/OnlyOffice/Editor.spec.jsx b/src/modules/views/OnlyOffice/Editor.spec.jsx index f76e57af06..cd5a5474fe 100644 --- a/src/modules/views/OnlyOffice/Editor.spec.jsx +++ b/src/modules/views/OnlyOffice/Editor.spec.jsx @@ -44,6 +44,14 @@ jest.mock('cozy-viewer', () => ({ default: () =>
})) +jest.mock('@/lib/ViewSwitcherContext', () => ({ + ViewSwitcherContextProvider: ({ children }) => children, + useViewSwitcherContext: jest.fn(() => ({ + viewType: 'list', + switchView: jest.fn() + })) +})) + const client = createMockClient({}) client.plugins = { realtime: { diff --git a/src/queries/index.ts b/src/queries/index.ts index cdd0fb6e9a..7e28070cf4 100644 --- a/src/queries/index.ts +++ b/src/queries/index.ts @@ -5,7 +5,8 @@ import { SHARED_DRIVES_DIR_ID, TRASH_DIR_ID } from '@/constants/config' import { DOCTYPE_FILES_ENCRYPTION, DOCTYPE_ALBUMS, - DOCTYPE_FILES_SETTINGS + DOCTYPE_FILES_SETTINGS, + DOCTYPE_DRIVE_SETTINGS } from '@/lib/doctypes' import { formatFolderQueryId } from '@/lib/queries' @@ -632,3 +633,15 @@ export const buildSharedDriveIdQuery: QueryBuilder< enabled: !!driveId } }) + +/** + * Drive application settings query + * + * @type {QueryConfig} + */ +export const getDriveSettingQuery: QueryConfig = { + definition: () => Q(DOCTYPE_DRIVE_SETTINGS), + options: { + as: DOCTYPE_DRIVE_SETTINGS + } +}