zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

page.test.exs (6735B)


      1 # Zenflows is designed to implement the Valueflows vocabulary,
      2 # written and maintained by srfsh <info@dyne.org>.
      3 # Copyright (C) 2021-2023 Dyne.org foundation <foundation@dyne.org>.
      4 #
      5 # This program is free software: you can redistribute it and/or modify
      6 # it under the terms of the GNU Affero General Public License as published by
      7 # the Free Software Foundation, either version 3 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU Affero General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU Affero General Public License
     16 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
     17 
     18 defmodule ZenflowsTest.DB.Page do
     19 use ZenflowsTest.Help.EctoCase, async: true
     20 
     21 # What we are testing here is a bit interesting.  Because, you see,
     22 # what we actually care about is dependant on the number of records we
     23 # ask for (referred to by "num" from now on).  This is because of we
     24 # always try to fetch num+1 records.  This basically means that we'll
     25 # have a table of possible cases:
     26 #
     27 # num | len(edges)
     28 # ----+-----------
     29 # 0   | 0
     30 # 0   | 1
     31 # ----+-----------
     32 # 1   | 0
     33 # 1   | 1
     34 # 1   | 2
     35 # ----+-----------
     36 # 2   | 0
     37 # 2   | 1
     38 # 2   | 2
     39 # 2   | 3
     40 # ----+-----------
     41 # 3   | 0
     42 # 3   | 1
     43 # 3   | 2
     44 # 3   | 3
     45 # 3   | 4
     46 # ----+-----------
     47 # 4   | 0
     48 # 4   | 1
     49 # 4   | 2
     50 # 4   | 3
     51 # 4   | 4
     52 # 4   | 5
     53 
     54 # Here, we cover the cases of:
     55 # num | len(edges)
     56 # ----+-----------
     57 # 0   | 0
     58 # 1   | 0
     59 # 2   | 0
     60 # 3   | 0
     61 # 4   | 0
     62 test "num>=0 && len(edges)==0:" do
     63 	Enum.each(0..10, fn n ->
     64 		assert %{data: %{"people" => data}} =
     65 			run!("""
     66 				query ($n: Int!) {
     67 					people (first: $n) {...people}
     68 				}
     69 			""", vars: %{"n" => n})
     70 
     71 		assert [] = Map.fetch!(data, "edges")
     72 
     73 		assert %{
     74 			"startCursor" => nil,
     75 			"endCursor" => nil,
     76 			"hasPreviousPage" => false,
     77 			"hasNextPage" => false,
     78 			"totalCount" => 0,
     79 			"pageLimit" => ^n,
     80 		} = Map.fetch!(data, "pageInfo")
     81 	end)
     82 end
     83 
     84 # Here, we cover the cases of:
     85 # num | len(edges)
     86 # ----+-----------
     87 # 1   | 1
     88 # 2   | 2
     89 # 3   | 3
     90 # 4   | 4
     91 test "num>=1 && len(edges)==num:" do
     92 	Enum.reduce(1..10, [], fn n, pers ->
     93 		last = %{id: last_cur} = Factory.insert!(:person)
     94 		pers = pers ++ [last]
     95 		[%{id: first_cur} | _] = pers
     96 
     97 		assert %{data: %{"people" => data}} =
     98 			run!("""
     99 				query ($n: Int!) {
    100 					people (first: $n) {...people}
    101 				}
    102 			""", vars: %{"n" => n})
    103 
    104 		edges = Map.fetch!(data, "edges")
    105 		assert length(edges) == n
    106 
    107 		assert %{
    108 			"startCursor" => ^first_cur,
    109 			"endCursor" => ^last_cur,
    110 			"hasPreviousPage" => false,
    111 			"hasNextPage" => false,
    112 			"totalCount" => ^n,
    113 			"pageLimit" => ^n,
    114 		} = Map.fetch!(data, "pageInfo")
    115 
    116 		pers
    117 	end)
    118 end
    119 
    120 # Here, we cover the cases of:
    121 # num | len(edges)
    122 # ----+-----------
    123 # 0   | 1
    124 # 1   | 2
    125 # 2   | 3
    126 # 3   | 4
    127 # 4   | 5
    128 test "num>=0 && len(edges)==num+1:" do
    129 	Enum.reduce(0..10, [], fn n, pers ->
    130 		pers = pers ++ [Factory.insert!(:person)]
    131 		{tmp, _} = Enum.split(pers, n)
    132 		first = List.first(tmp)
    133 		last = List.last(tmp)
    134 		first_cur = if first != nil, do: first.id, else: nil
    135 		last_cur = if last != nil, do: last.id, else: nil
    136 
    137 		assert %{data: %{"people" => data}} =
    138 			run!("""
    139 				query ($n: Int!) {
    140 					people (first: $n) {...people}
    141 				}
    142 			""", vars: %{"n" => n})
    143 
    144 		edges = Map.fetch!(data, "edges")
    145 		assert length(edges) == n
    146 
    147 		assert %{
    148 			"startCursor" => ^first_cur,
    149 			"endCursor" => ^last_cur,
    150 			"hasPreviousPage" => false,
    151 			"hasNextPage" => true,
    152 			"totalCount" => ^n,
    153 			"pageLimit" => ^n,
    154 		} = Map.fetch!(data, "pageInfo")
    155 
    156 		pers
    157 	end)
    158 end
    159 
    160 # Here, we cover the last case, which prooves we cover all the cases
    161 # (this is so because of the fact that we only deal with len(edges)<num
    162 # cases, where num>=1):
    163 # num | len(edges)
    164 # ----+-----------
    165 # 2   | 1
    166 # ----+-----------
    167 # 3   | 1
    168 # 3   | 2
    169 # ----+-----------
    170 # 4   | 1
    171 # 4   | 2
    172 # 4   | 3
    173 test "num>=2 && len(edges)>=0 && len(edges)<num:" do
    174 	Enum.reduce(1..9, [], fn e, pers ->
    175 		pers = pers ++ [Factory.insert!(:person)]
    176 
    177 		Enum.each(2..10, fn n ->
    178 			if e < n do
    179 				assert %{data: %{"people" => data}} =
    180 					run!("""
    181 						query ($n: Int!) {
    182 							people (first: $n) {...people}
    183 						}
    184 					""", vars: %{"n" => n})
    185 
    186 				edges = Map.fetch!(data, "edges")
    187 				assert length(edges) == e
    188 
    189 				%{id: first_cur} = List.first(pers)
    190 				%{id: last_cur} = List.last(pers)
    191 
    192 				assert %{
    193 					"startCursor" => ^first_cur,
    194 					"endCursor" => ^last_cur,
    195 					"hasPreviousPage" => false,
    196 					"hasNextPage" => false,
    197 					"totalCount" => ^e,
    198 					"pageLimit" => ^n,
    199 				} = Map.fetch!(data, "pageInfo")
    200 			end
    201 		end)
    202 
    203 		pers
    204 	end)
    205 end
    206 
    207 # We're dealing with cursors here now.  Most of the cases are the
    208 # same as the ones without the cursors, so we omit them.
    209 
    210 # Here, we cover the cases of:
    211 # num | len(edges)
    212 # ----+-----------
    213 # 1   | 1
    214 # 2   | 2
    215 # 3   | 3
    216 # 4   | 4
    217 test "with cursor: num>=1 && len(edges)==num:" do
    218 	Enum.each(1..10, fn n ->
    219 		p = Factory.insert!(:person)
    220 
    221 		assert %{data: %{"people" => data}} =
    222 			run!("""
    223 				query ($cur: ID! $n: Int!) {
    224 					people (after: $cur first: $n) {...people}
    225 				}
    226 			""", vars: %{"n" => n, "cur" => p.id})
    227 
    228 		assert [] = Map.fetch!(data, "edges")
    229 
    230 		assert %{
    231 			"startCursor" => nil,
    232 			"endCursor" => nil,
    233 			"hasPreviousPage" => true, # spec says so if we can't determine
    234 			"hasNextPage" => false,
    235 			"totalCount" => 0,
    236 			"pageLimit" => ^n,
    237 		} = Map.fetch!(data, "pageInfo")
    238 	end)
    239 end
    240 
    241 # Here, we cover the cases of:
    242 # num | len(edges)
    243 # ----+-----------
    244 # 1   | 2
    245 # 2   | 3
    246 # 3   | 4
    247 # 4   | 5
    248 test "with cursor: num>=1 && len(edges)==num+1:" do
    249 	pers = [Factory.insert!(:person)]
    250 	Enum.reduce(1..10, pers, fn n, pers ->
    251 		%{id: after_cur} = List.last(pers)
    252 		last = %{id: last_cur} = Factory.insert!(:person)
    253 		pers = pers ++ [last]
    254 
    255 		assert %{data: %{"people" => data}} =
    256 			run!("""
    257 				query ($cur: ID! $n: Int!) {
    258 					people (after: $cur first: $n) {...people}
    259 				}
    260 			""", vars: %{"n" => n, "cur" => after_cur})
    261 
    262 		assert [_] = Map.fetch!(data, "edges")
    263 
    264 		assert %{
    265 			"startCursor" => ^last_cur,
    266 			"endCursor" => ^last_cur,
    267 			"hasPreviousPage" => true, # spec
    268 			"hasNextPage" => false,
    269 			"totalCount" => 1,
    270 			"pageLimit" => ^n,
    271 		} = Map.fetch!(data, "pageInfo")
    272 
    273 		pers
    274 	end)
    275 end
    276 
    277 @spec run!(String.t(), Keyword.t()) :: Absinthe.run_result()
    278 def run!(doc, opts \\ []) do
    279 	"""
    280 	#{doc}
    281 	fragment people on PersonConnection {
    282 		pageInfo {
    283 			startCursor
    284 			endCursor
    285 			hasPreviousPage
    286 			hasNextPage
    287 			totalCount
    288 			pageLimit
    289 		}
    290 		edges {
    291 			cursor
    292 			node {id}
    293 		}
    294 	}
    295 	"""
    296 	|> ZenflowsTest.Help.AbsinCase.run!(opts)
    297 end
    298 end