slack_messaging/blocks/elements/
overflow_menu.rs1use crate::composition_objects::{ConfirmationDialog, Opt, Plain, Text, types::UrlAvailable};
2use crate::validators::*;
3
4use serde::Serialize;
5use slack_messaging_derive::Builder;
6
7#[derive(Debug, Clone, Serialize, PartialEq, Builder)]
84#[serde(tag = "type", rename = "overflow")]
85pub struct OverflowMenu {
86 #[serde(skip_serializing_if = "Option::is_none")]
87 #[builder(validate("text::max_255"))]
88 pub(crate) action_id: Option<String>,
89
90 #[builder(push_item = "option", validate("required", "list::max_item_5"))]
91 pub(crate) options: Option<Vec<Opt<Text<Plain>, UrlAvailable>>>,
92
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub(crate) confirm: Option<ConfirmationDialog>,
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use crate::composition_objects::test_helpers::{confirm, plain_text};
101 use crate::errors::*;
102
103 #[test]
104 fn it_implements_builder() {
105 let expected = OverflowMenu {
106 action_id: Some("overflow_menu_0".into()),
107 options: Some(vec![option("opt0", "val0"), option("opt1", "val1")]),
108 confirm: Some(confirm()),
109 };
110
111 let val = OverflowMenu::builder()
112 .set_action_id(Some("overflow_menu_0"))
113 .set_options(Some(vec![option("opt0", "val0"), option("opt1", "val1")]))
114 .set_confirm(Some(confirm()))
115 .build()
116 .unwrap();
117
118 assert_eq!(val, expected);
119
120 let val = OverflowMenu::builder()
121 .action_id("overflow_menu_0")
122 .options(vec![option("opt0", "val0"), option("opt1", "val1")])
123 .confirm(confirm())
124 .build()
125 .unwrap();
126
127 assert_eq!(val, expected);
128 }
129
130 #[test]
131 fn it_implements_push_item_method() {
132 let expected = OverflowMenu {
133 action_id: None,
134 options: Some(vec![option("opt0", "val0"), option("opt1", "val1")]),
135 confirm: None,
136 };
137
138 let val = OverflowMenu::builder()
139 .option(option("opt0", "val0"))
140 .option(option("opt1", "val1"))
141 .build()
142 .unwrap();
143
144 assert_eq!(val, expected);
145 }
146
147 #[test]
148 fn it_requires_action_id_less_than_255_characters_long() {
149 let err = OverflowMenu::builder()
150 .option(option("opt0", "val0"))
151 .action_id("a".repeat(256))
152 .build()
153 .unwrap_err();
154 assert_eq!(err.object(), "OverflowMenu");
155
156 let errors = err.field("action_id");
157 assert!(errors.includes(ValidationErrorKind::MaxTextLength(255)));
158 }
159
160 #[test]
161 fn it_requires_options_field() {
162 let err = OverflowMenu::builder().build().unwrap_err();
163 assert_eq!(err.object(), "OverflowMenu");
164
165 let errors = err.field("options");
166 assert!(errors.includes(ValidationErrorKind::Required));
167 }
168
169 #[test]
170 fn it_requires_options_item_size_less_than_5() {
171 let err = OverflowMenu::builder()
172 .options(vec![
173 option("opt0", "val0"),
174 option("opt1", "val1"),
175 option("opt2", "val2"),
176 option("opt3", "val3"),
177 option("opt4", "val4"),
178 option("opt5", "val5"),
179 ])
180 .build()
181 .unwrap_err();
182 assert_eq!(err.object(), "OverflowMenu");
183
184 let errors = err.field("options");
185 assert!(errors.includes(ValidationErrorKind::MaxArraySize(5)));
186 }
187
188 fn option(text: impl Into<String>, value: impl Into<String>) -> Opt<Text<Plain>, UrlAvailable> {
189 Opt {
190 phantom: std::marker::PhantomData,
191 text: Some(plain_text(text)),
192 value: Some(value.into()),
193 description: None,
194 url: None,
195 }
196 }
197}