Coverage for tests/tests_vite_integration.py: 100%

102 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-17 22:07 +0000

1from unittest import TestCase 

2import json 

3from shutil import rmtree 

4from typing import cast 

5from urllib.parse import urlparse 

6from pathlib import Path 

7from webapp.vite_integration.impl import ( 

8 ProdViteIntegration, 

9 DevViteIntegration, 

10) 

11import webapp.vite_integration.exceptions as vite_exceptions 

12 

13MOCK_OUTPUT_PATH = "/tmp/python_vite_test" 

14MOCK_ASSET_PATH = "test/path/for/asset.ts" 

15MOCK_SCSS_PATH = "test/path/for/styles.scss" 

16MOCK_MANIFEST = { 

17 "_dependency.js": {"file": "chunks/dependency.js", "name": "dependency"}, 

18 "_chunk.js": { 

19 "file": "chunks/chunk.js", 

20 "name": "chunk", 

21 "imports": ["_dependency.js"], 

22 "css": ["assets/styles.css"], 

23 }, 

24 "test/path/for/asset.ts": { 

25 "file": "asset.js", 

26 "name": "asset", 

27 "src": "test/path/for/asset.ts", 

28 "isEntry": True, 

29 "imports": [ 

30 "_chunk.js", 

31 ], 

32 }, 

33 "test/path/for/styles.scss": { 

34 "file": "assets/styles.css", 

35 "src": "test/path/for/styles.scss", 

36 "isEntry": True, 

37 "names": ["styles.css"], 

38 }, 

39} 

40 

41 

42class TestsDevViteIntegration(TestCase): 

43 def setUp(self): 

44 self.vite = DevViteIntegration() 

45 

46 def tests_dev_tools(self): 

47 dev_tools = self.vite.get_dev_tools() 

48 assert "@vite/client" in dev_tools 

49 assert "@react-refresh" in dev_tools 

50 

51 def tests_get_asset_url(self): 

52 url = self.vite.get_asset_url(MOCK_ASSET_PATH) 

53 assert MOCK_ASSET_PATH in url 

54 parsed = urlparse(url) 

55 assert parsed.scheme == "http" 

56 assert parsed.netloc.startswith("localhost:") 

57 assert parsed.path == f"/{MOCK_ASSET_PATH}" 

58 assert parsed.params == "" 

59 assert parsed.query == "" 

60 assert parsed.fragment == "" 

61 

62 def tests_get_imported_chunks(self): 

63 assert len(self.vite.get_imported_chunks(MOCK_ASSET_PATH)) == 0 

64 

65 def tests_get_imported_css(self): 

66 assert len(self.vite.get_imported_css(MOCK_ASSET_PATH)) == 0 

67 

68 

69class TestsProdViteIntegration(TestCase): 

70 def setUp(self): 

71 # create a fake Vite output directory 

72 manifest_path = Path(f"{MOCK_OUTPUT_PATH}/.vite/manifest.json") 

73 manifest_path.parent.mkdir(exist_ok=True, parents=True) 

74 with manifest_path.open("w+") as file: 

75 file.write(json.dumps(MOCK_MANIFEST)) 

76 

77 for entry in MOCK_MANIFEST.values(): 

78 file = cast(dict, entry).get("file", "") 

79 file_path = Path(f"{MOCK_OUTPUT_PATH}/{file}") 

80 file_path.parent.mkdir(exist_ok=True, parents=True) 

81 with file_path.open("w+") as file: 

82 file.write("") 

83 

84 # inject the mocks in the static class scope before initalizing 

85 ProdViteIntegration.OUT_DIR = MOCK_OUTPUT_PATH 

86 

87 def tearDown(self): 

88 rmtree(MOCK_OUTPUT_PATH) 

89 

90 def tests_good_manifest_file(self): 

91 # attempt to init 

92 ProdViteIntegration() 

93 

94 def tests_bad_manifest_file(self): 

95 # try to init a ProdViteIntegration instance with a bad manifest file 

96 

97 ProdViteIntegration.manifest = None # reset the manifest instance 

98 old_manifest_name = ProdViteIntegration.BUILD_MANIFEST 

99 

100 ProdViteIntegration.BUILD_MANIFEST = "file/that/does/not/exist" 

101 

102 with self.assertRaises(vite_exceptions.ManifestPathException): 

103 self.vite = ProdViteIntegration() 

104 

105 ProdViteIntegration.BUILD_MANIFEST = old_manifest_name 

106 

107 def tests_dev_tools(self): 

108 vite = ProdViteIntegration() 

109 dev_tools = vite.get_dev_tools() 

110 assert dev_tools == "" 

111 

112 def tests_get_asset_url__bad_asset(self): 

113 vite = ProdViteIntegration() 

114 with self.assertRaises(vite_exceptions.ManifestContentException): 

115 vite.get_asset_url("this_asset_does_not_exist.ts") 

116 

117 def tests_get_asset_url__bad_path(self): 

118 # try to load an asset declared in the manifest but without a real 

119 # file backing it 

120 # load a proper manifest... 

121 ProdViteIntegration.manifest = MOCK_MANIFEST 

122 # but also load a broken OUT_DIR path 

123 ProdViteIntegration.OUT_DIR = "/tmp/path/does/not/exist" 

124 

125 vite = ProdViteIntegration() 

126 with self.assertRaises(vite_exceptions.AssetPathException): 

127 vite.get_asset_url(MOCK_ASSET_PATH) 

128 

129 # cleanup 

130 ProdViteIntegration.OUT_DIR = MOCK_OUTPUT_PATH 

131 ProdViteIntegration.manifest = None 

132 

133 def tests_get_asset_url__is_not_ts(self): 

134 vite = ProdViteIntegration() 

135 url = vite.get_asset_url(MOCK_ASSET_PATH) 

136 assert MOCK_ASSET_PATH not in url # source asset is a .ts file 

137 assert url.endswith(".js") # dist asset is a .js file 

138 

139 def tests_get_asset_url__is_not_scss(self): 

140 vite = ProdViteIntegration() 

141 url = vite.get_asset_url(MOCK_SCSS_PATH) 

142 assert MOCK_SCSS_PATH not in url # source asset is a .scss file 

143 assert url.endswith(".css") # dist asset is a .css file 

144 

145 def tests_get_imported_chunks__bad_asset(self): 

146 vite = ProdViteIntegration() 

147 with self.assertRaises(vite_exceptions.ManifestContentException): 

148 vite.get_imported_chunks("this_asset_does_not_exist.ts") 

149 

150 def tests_get_imported_chunks__bad_path(self): 

151 # try to load chunks for an asset declared in the manifest but 

152 # without a real file backing it 

153 # load a proper manifest... 

154 ProdViteIntegration.manifest = MOCK_MANIFEST 

155 # but also load a broken OUT_DIR path 

156 ProdViteIntegration.OUT_DIR = "/tmp/path/does/not/exist" 

157 

158 vite = ProdViteIntegration() 

159 with self.assertRaises(vite_exceptions.AssetPathException): 

160 vite.get_imported_chunks(MOCK_ASSET_PATH) 

161 

162 # cleanup 

163 ProdViteIntegration.OUT_DIR = MOCK_OUTPUT_PATH 

164 ProdViteIntegration.manifest = None 

165 

166 def tests_get_imported_chunks(self): 

167 vite = ProdViteIntegration() 

168 js_entries = filter( 

169 lambda x: x["file"].endswith(".js"), MOCK_MANIFEST.values() 

170 ) 

171 assert len(vite.get_imported_chunks(MOCK_ASSET_PATH)) == ( 

172 len(list(js_entries)) - 1 

173 ) 

174 

175 def tests_get_imported_css(self): 

176 vite = ProdViteIntegration() 

177 assert len(vite.get_imported_css(MOCK_ASSET_PATH)) == 1