1import { vol } from 'memfs';
2
3import { writeXMLAsync } from '../../utils/XML';
4import { buildResourceItem, readResourcesXMLAsync } from '../Resources';
5import {
6  getProjectStylesXMLPathAsync,
7  getStyleParent,
8  getStylesItem,
9  removeStylesItem,
10  setStylesItem,
11} from '../Styles';
12jest.mock('fs');
13
14const mockStyles = `
15<?xml
16  version="1.0"
17  encoding="UTF-8"
18  standalone="yes"
19?>
20<resources>
21  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
22    <item name="android:textColor">#000000</item>
23    <item name="android:windowTranslucentStatus">true</item>
24    <item name="colorPrimary">@color/colorPrimary</item>
25  </style>
26  <style name="Theme.App.SplashScreen" parent="AppTheme">
27    <item name="android:windowBackground">@drawable/splashscreen</item>
28  </style>
29</resources>`;
30
31describe('Styles', () => {
32  beforeAll(async () => {
33    const directoryJSON = {
34      './app/android/app/src/main/res/values/styles.xml': mockStyles,
35      './empty/android/app/src/main/res/values/styles.xml': '<resources></resources>',
36    };
37    vol.fromJSON(directoryJSON, '/');
38  });
39  afterAll(async () => {
40    vol.reset();
41  });
42
43  it(`sets a style on an empty resource item`, async () => {
44    const stylesPath = await getProjectStylesXMLPathAsync('/empty')!;
45    const xml = await readResourcesXMLAsync({ path: stylesPath });
46    const parent = { name: 'AppTheme', parent: 'Theme.AppCompat.Light.NoActionBar' };
47    setStylesItem({
48      xml,
49      parent,
50      item: buildResourceItem({ name: 'android:textColor', value: '#fff000' }),
51    });
52    await writeXMLAsync({ path: stylesPath, xml });
53
54    const modifiedXml = await readResourcesXMLAsync({ path: stylesPath });
55
56    expect(getStyleParent(modifiedXml, parent)).toStrictEqual({
57      $: { name: 'AppTheme', parent: 'Theme.AppCompat.Light.NoActionBar' },
58      item: [{ $: { name: 'android:textColor' }, _: '#fff000' }],
59    });
60  });
61  it(`changes the value of a style`, async () => {
62    const stylesPath = await getProjectStylesXMLPathAsync('/app')!;
63    const xml = await readResourcesXMLAsync({ path: stylesPath });
64    const parent = { name: 'Theme.App.SplashScreen', parent: 'AppTheme' };
65    setStylesItem({
66      xml,
67      parent,
68      item: buildResourceItem({ name: 'android:textColor', value: '#ffffff' }),
69    });
70    await writeXMLAsync({ path: stylesPath, xml });
71
72    const modifiedXml = await readResourcesXMLAsync({ path: stylesPath });
73
74    expect(getStyleParent(modifiedXml, parent)).toStrictEqual({
75      $: { name: 'Theme.App.SplashScreen', parent: 'AppTheme' },
76      item: [
77        { $: { name: 'android:windowBackground' }, _: '@drawable/splashscreen' },
78        {
79          $: {
80            name: 'android:textColor',
81          },
82          _: '#ffffff',
83        },
84      ],
85    });
86  });
87
88  it(`removes a value`, async () => {
89    const stylesPath = await getProjectStylesXMLPathAsync('/app')!;
90    const xml = await readResourcesXMLAsync({ path: stylesPath });
91    const parent = { name: 'Theme.App.SplashScreen', parent: 'AppTheme' };
92    expect(getStylesItem({ xml, parent, name: 'android:textColor' })).toStrictEqual({
93      $: {
94        name: 'android:textColor',
95      },
96      _: '#ffffff',
97    });
98
99    removeStylesItem({
100      xml,
101      parent,
102      name: 'android:textColor',
103    });
104    expect(getStylesItem({ xml, parent, name: 'android:textColor' })).toBe(null);
105  });
106});
107