fields.test.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. import { createTheme, toDataFrame } from '@grafana/data';
  2. import { prepareCandlestickFields } from './fields';
  3. import { CandlestickOptions, VizDisplayMode } from './models.gen';
  4. const theme = createTheme();
  5. describe('Candlestick data', () => {
  6. const options: CandlestickOptions = {} as CandlestickOptions;
  7. it('require a time field', () => {
  8. const info = prepareCandlestickFields(
  9. [
  10. toDataFrame({
  11. name: 'hello',
  12. columns: ['a', 'b', 'c'],
  13. rows: [
  14. ['A', 2, 3],
  15. ['B', 4, 5],
  16. ['C', 6, 7],
  17. ],
  18. }),
  19. ],
  20. options,
  21. theme
  22. );
  23. expect(info).toBeNull();
  24. });
  25. it('will match common names by default', () => {
  26. const info = prepareCandlestickFields(
  27. [
  28. toDataFrame({
  29. fields: [
  30. { name: 'time', values: [1] },
  31. { name: 'a', values: [1] },
  32. { name: 'min', values: [1] },
  33. { name: 'MAX', values: [1] },
  34. { name: 'v', values: [1] },
  35. ],
  36. }),
  37. ],
  38. options,
  39. theme
  40. );
  41. expect(info?.names).toMatchInlineSnapshot(`
  42. Object {
  43. "close": "Next open",
  44. "high": "MAX",
  45. "low": "min",
  46. "open": "a",
  47. "volume": "v",
  48. }
  49. `);
  50. });
  51. it('will support simple timeseries (poorly)', () => {
  52. const info = prepareCandlestickFields(
  53. [
  54. toDataFrame({
  55. fields: [
  56. {
  57. name: 'time',
  58. values: [1, 2, 3],
  59. },
  60. {
  61. name: 'value',
  62. values: [4, 5, 6],
  63. },
  64. ],
  65. }),
  66. ],
  67. options,
  68. theme
  69. )!;
  70. expect(info.open).toBeDefined();
  71. expect(info.open).toEqual(info.high);
  72. expect(info.open).toEqual(info.low);
  73. expect(info.open).not.toEqual(info.close);
  74. expect(info.names.close).toMatchInlineSnapshot(`"Next open"`);
  75. // Close should be offset by one and dupliate last point
  76. expect({ open: info.open!.values.toArray(), close: info.close!.values.toArray() }).toMatchInlineSnapshot(`
  77. Object {
  78. "close": Array [
  79. 5,
  80. 6,
  81. 6,
  82. ],
  83. "open": Array [
  84. 4,
  85. 5,
  86. 6,
  87. ],
  88. }
  89. `);
  90. });
  91. it('will create open from previous close', () => {
  92. const info = prepareCandlestickFields(
  93. [
  94. toDataFrame({
  95. fields: [
  96. {
  97. name: 'time',
  98. values: [1, 2, 3, 4, 5],
  99. },
  100. {
  101. name: 'close',
  102. values: [1, 2, 3, 4, 5],
  103. },
  104. ],
  105. }),
  106. ],
  107. options,
  108. theme
  109. )!;
  110. expect(info.open!.values.toArray()).toEqual([1, 1, 2, 3, 4]);
  111. expect(info.close!.values.toArray()).toEqual([1, 2, 3, 4, 5]);
  112. });
  113. it('will unmap high & low fields in volume-only mode', () => {
  114. const options: CandlestickOptions = {
  115. mode: VizDisplayMode.Volume,
  116. includeAllFields: true,
  117. } as CandlestickOptions;
  118. const info = prepareCandlestickFields(
  119. [
  120. toDataFrame({
  121. fields: [
  122. {
  123. name: 'time',
  124. values: [1, 2, 3],
  125. },
  126. {
  127. name: 'low',
  128. values: [4, 5, 6],
  129. },
  130. {
  131. name: 'high',
  132. values: [7, 8, 9],
  133. },
  134. {
  135. name: 'open',
  136. values: [4, 5, 6],
  137. },
  138. {
  139. name: 'close',
  140. values: [7, 8, 9],
  141. },
  142. {
  143. name: 'volume',
  144. values: [70, 80, 90],
  145. },
  146. {
  147. name: 'extra',
  148. values: [10, 20, 30],
  149. },
  150. ],
  151. }),
  152. ],
  153. options,
  154. theme
  155. )!;
  156. expect(info.open).toBeDefined();
  157. expect(info.close).toBeDefined();
  158. expect(info.volume).toBeDefined();
  159. expect(info.frame.fields).toContain(info.open);
  160. expect(info.frame.fields).toContain(info.close);
  161. expect(info.frame.fields).toContain(info.volume);
  162. expect(info.high).toBeUndefined();
  163. expect(info.low).toBeUndefined();
  164. // includeAllFields: true
  165. expect(info.frame.fields.find((f) => f.name === 'high')).toBeDefined();
  166. expect(info.frame.fields.find((f) => f.name === 'low')).toBeDefined();
  167. expect(info.frame.fields.find((f) => f.name === 'extra')).toBeDefined();
  168. });
  169. it('will unmap volume field in candles-only mode', () => {
  170. const options: CandlestickOptions = {
  171. mode: VizDisplayMode.Candles,
  172. includeAllFields: false,
  173. } as CandlestickOptions;
  174. const info = prepareCandlestickFields(
  175. [
  176. toDataFrame({
  177. fields: [
  178. {
  179. name: 'time',
  180. values: [1, 2, 3],
  181. },
  182. {
  183. name: 'low',
  184. values: [4, 5, 6],
  185. },
  186. {
  187. name: 'high',
  188. values: [7, 8, 9],
  189. },
  190. {
  191. name: 'open',
  192. values: [4, 5, 6],
  193. },
  194. {
  195. name: 'close',
  196. values: [7, 8, 9],
  197. },
  198. {
  199. name: 'volume',
  200. values: [70, 80, 90],
  201. },
  202. {
  203. name: 'extra',
  204. values: [10, 20, 30],
  205. },
  206. ],
  207. }),
  208. ],
  209. options,
  210. theme
  211. )!;
  212. expect(info.open).toBeDefined();
  213. expect(info.close).toBeDefined();
  214. expect(info.high).toBeDefined();
  215. expect(info.low).toBeDefined();
  216. expect(info.volume).toBeUndefined();
  217. expect(info.frame.fields).toContain(info.open);
  218. expect(info.frame.fields).toContain(info.close);
  219. expect(info.frame.fields).toContain(info.high);
  220. expect(info.frame.fields).toContain(info.low);
  221. // includeAllFields: false
  222. expect(info.frame.fields.find((f) => f.name === 'volume')).toBeUndefined();
  223. expect(info.frame.fields.find((f) => f.name === 'extra')).toBeUndefined();
  224. });
  225. it("will not remove open field from frame when it's also mapped to high in volume-only mode", () => {
  226. const options: CandlestickOptions = {
  227. mode: VizDisplayMode.Volume,
  228. includeAllFields: false,
  229. } as CandlestickOptions;
  230. const info = prepareCandlestickFields(
  231. [
  232. toDataFrame({
  233. fields: [
  234. {
  235. name: 'time',
  236. values: [1, 2, 3],
  237. },
  238. {
  239. name: 'open',
  240. values: [4, 5, 6],
  241. },
  242. {
  243. name: 'close',
  244. values: [7, 8, 9],
  245. },
  246. {
  247. name: 'volume',
  248. values: [70, 80, 90],
  249. },
  250. {
  251. name: 'extra',
  252. values: [10, 20, 30],
  253. },
  254. ],
  255. }),
  256. ],
  257. options,
  258. theme
  259. )!;
  260. expect(info.open).toBeDefined();
  261. expect(info.close).toBeDefined();
  262. expect(info.volume).toBeDefined();
  263. expect(info.frame.fields).toContain(info.open);
  264. expect(info.frame.fields).toContain(info.close);
  265. expect(info.frame.fields).toContain(info.volume);
  266. // includeAllFields: false
  267. expect(info.frame.fields.find((f) => f.name === 'extra')).toBeUndefined();
  268. });
  269. });